#!/usr/bin/perl -w  -d
use strict;
use Carp;

my $progname = "cDisko";
my $progvers = "3.0c"; # the c is for client

#######################################################################
###  Disko: A GUI for vsib_record
###
###  History:
###   16-Sep_2005 : v1.0 : Initial release    - Jim Lovell
###
###   03-Feb_2006 : v1.0c : Changed to interact with the VSIB
###                         recorder server    - Jamie Stevens
###
###   21-Apr_2006 : v1.1c : Bugfixes and new server features
###                         implemented after March run - JS
###
###   19-Jul_2006 : v1.2c : New and improved features:
###                         - new channel selection modes, dependent
###                           on number of recorders and bandwidth
###                         - can now automatically restrict start
###                           times to be on 10s boundaries
###                         - can control the disk cleaner
###                         - update time selectable
###                         - start date/time now easier to use
###                         - experiment loaders are now comboboxes
###                           to save space on the GUI
###                         (note new features requires version 1.35
###                          of the recorder_server - JS)
###
###   10-Oct_2006 : v1.3c : Some fixes suggested by Chris Phillips
###                         - server_listener now needs to be
###                           somewhere in the path, no longer
###                           assumed by default to be in the
###                           current directory
###                         - added a check to stop the message
###                           "- not numeric"
###                         - all background colour options removed
###                           (thanks Chris!)
###                         - added check for name resolution success
###                           (thanks Chris!)
###                         - added checks for parameters that should
###                           be in ~/.disko_config (thanks Chris!)
###                         - logfiles are now written to the
###                           log_dir listed in ~/.disko_config
###
###   11-Jan_2007 : v2.0c : New options added to support new
###                         recorder_server v1.50, and a substantial
###                         recode to make everything nicer internally
###                         and to simplify future changes.
###
###   28-Feb_2007 : v2.1c : Further improvements for usability, based
###                         on CJP suggestions.
###                         - only errors shown in message window
###                         - changed "Rounded start" label
###                         - recording/cleaning status up the top now
###                           and "RECORDING" appears in title bar
###                         - Now+2m changed to Now+10s
###                         - info/stats about last recording stay
###                           after recording finishes (relies on new
###                           server capability)
###                         - disk unit no longer selectable, but
###                           changes between G and M automatically
###                         - added newly supported compression modes
###                         - settings that affect the bitrate always
###                           trigger a server query
###
###   31-May_2007 : v2.2c : Changes due to recorder_server modification
###                         and CJP suggestions.
###                         - moved Huygens and eVLBI mode switches to
###                           main window
###                         - advanced and eVLBI windows now buttons,
###                           not checkboxes, in menu
###                         - added newly supported compression modes
###                         - made Huygen's cable compression modes
###                           include single DAS modes as well
###                         - modified server parsing routines to
###                           accommodate recorder_server v1.54,
###                           old server versions will no longer work
###                           with this cDisko
###
###   09-Oct_2007 : v2.3c : Changes for eVLBI interface.
###                         - now displays and allows for selection of
###                           remote disk when eVLBI mode is enabled
###                           and remote server is accessible
###                         - start recording button now starts
###                           eVLBI receiver on remote host at the
###                           same time
###                         - the stop button stops eVLBI receiver
###                         - eVLBI mode gets information from remote
###                           host when applicable (eg. duration,
###                           experiment name, fringe-check flag) and
###                           sets them as well
###
###   30-Oct_2007 : v2.4c : Changes for eVLBI interface CJP suggestions
###                         - added Mark5B recording toggle
###                         - added extra UDP field for eVLBI when
###                           Mark5B recording is enabled
###                         - added eVLBI mode, changed Local/Remote
###                           disk recording selection mode
###                         - cDisko now logs which disk & type it is
###                           recording to
###                         - added Set Server button to send settings
###                           to the server
###                         - changed the way cDisko stops updating the
###                           statistics panel after recording stops
###
###   21-Aug_2009 : v2.7c : Changes to support new recorder_server
###                         features:
###                         - disks are no longer shown if they are
###                           not mounted, and will automatically
###                           appear and disappear from cDisko now
###                         - change recording state to "Recording
###                           pending" when vsib_record has been
###                           started, but the scheduled start time has
###                           not yet arrived
###                         - Scheduled start now gets disabled after
###                           starting a recording so it doesn't stop
###                           a subsequent recording
###                         - add xxooooxx and ooxxxxoo compression
###                         - keep log to less than 100 lines long
###
###   04-Sep_2009 : v2.8c : Enable another compression mode:
###                         - xo, 16 bits, channels 5-8
###
###   19-Jan_2009 : v2.9c : Changes to support new recorder_server
###                         features:
###                         - ignore errors generated when setting
###                           start time and date so an attempt to
###                           start recording is always made even if
###                           the start time is in the past
###                         - now correctly reads and sets disks in
###                           the new recorder_server fashion
###                         - reads list of remote recorders from the
###                           .disko_config file, and puts them in a
###                           menu; selecting them adds them to the
###                           recorder, deselecting removes them
###
###   21-Jan_2009 : v3.0c : Major style changes, mainly due to requests
###                         and to support new ways of operating with
###                         recorder_server:
###                         - got rid of cleaning status (no more
###                           cleaning is possible)
###                         - got rid of local/remote/eVLBI modes as
###                           recorder_server no longer differentiates
###                           these modes, and allows single point of
###                           configuration
###                         - added more to eVLBI window; can now add
###                           new hosts, and enable/disable remote
###                           hosts in the server
###                         - added "Recording Information" window,
###                           which now contains the recording stats
###                           along with the settings that were used
###                           for that recording and details of the
###                           disk being used
###
#######################################################################


use Astro::Coord;
use Astro::Time;
use Config::Trivial;
use Env qw(HOME);
use Tk;
use Tk::BrowseEntry;
use Tk::Dialog;
use sigtrap;
use IO::Socket::INET;

# Debug messages
my $debug = 0;

# list of known antennas and their coordinates. Used for LST calculation
my %Antennas = (
		DSS43  => [-4460894.7273, 2682361.5296, -3674748.4238],
		DSS45  => [-4460935.4093, 2682765.7035, -3674381.2105],
		Hobart => [-3950236.7454, 2522347.5502, -4311562.5527],
		Ceduna => [-3753440.70,   3912708.30,   -3348066.90],
		Mopra  => [-4682768.6300, 2802619.0600, -3291759.9000],
		ATCA   => [-4751630.5370, 2791692.8690, -3200483.7470], #station W104
		Parkes => [-4554232.1122, 2816759.1425, -3454036.0058],
		Test   => [-4751630.5370, 2791692.8690, -3200483.7470], # Same as ATCA
		);
# Antenna abbreviations. Used for naming data files
my %Antenna_abbrev = (
		      DSS43  => "43",
		      DSS45  => "45",
		      Hobart => "Ho",
		      Ceduna => "Cd",
		      Mopra  => "Mp",
		      ATCA   => "At",
		      Parkes => "Pk",
		      Test => "Tt"
		      );
my @template_comments = ("--- Select ---",
			 "Antenna is on point",
			 "Antenna is off source",
			 "Antenna moving off source for pointing check",
			 "Wind stow. Antenna off point.",
			 "Manchester United 3, Arsenal 0"
			 );
my (%Current_Parameters,%Old_Parameters,%Server_Parameters);
my @remote_settable_parameters = ("fringecheck_flag",
				  "experiment_name",
				  "bandwidth",
				  "vsib_bits",
				  "compression",
				  "record_duration"
    );
my @settable_parameters = ("fringecheck_flag",
			   "experiment_name",
			   "bandwidth",
			   "vsib_bits",
			   "compression",
			   "record_duration",
			   "duration_unit",
			   "active_disk",
			   "auto_experiment",
			   "auto_rounding",
			   "clean_time",
			   "vsib_device",
			   "file_size",
			   "block_size",
			   "clock_rate",
			   "mark5b"
			   );
my @settable_window = ("all",
		       "all",
		       "all",
		       "all",
		       "all",
		       "all",
		       "all",
		       "all",
		       "all",
		       "all",
		       "all",
		       "advanced",
		       "advanced",
		       "advanced",
		       "advanced",
		       "all"
		       );
my @settable_types = ("number",
		      "string",
		      "number",
		      "number",
		      "string",
		      "number",
		      "string",
		      "string",
		      "number",
		      "number",
		      "string",
		      "string",
		      "string",
		      "number",
		      "number",
		      "number",
		      );
my @info_commands = ("status-server",
		     "status-record",
		     "status-settings",
		     "experiment-list",
		     "status-receiver",
		     "status-remotehosts",
		     "status-recsettings"
		     );

my $server_response;
my $communication_error;
my $template_comment = $template_comments[0];
my $n_retries=5;
my $disks_frame;
my $remote_frame;
my @disks_buttons;
my @disks_recorders;
my @disks_labels;
my @disks_sizes;
my @disks_remainings;
my @disks_lefts;
my @disks_times;
my @disks_spaces;
my $disks_display_label;
my $disks_warning_time=time;
my $evlbi_host_port="";
my $evlbi_mode="";
my $set_all_remote_options=0;
my $fringecheck_already_set=0;
my $recording_to_disk=-1;
my $last_num_disks=-1;
my $get_recorder_command=0;

my @available_compress_modes = ("oooo", "ooox", "ooxx", "oxox", "xxoo", "xxxx");
my @bandwidths = (1, 2, 4, 8, 16, 32, 64);
my $bandwidth = 16;
my @available_number_of_bits = (8, 16);

#############################################################################
# Standard mode definitions:
# These are the available modes. For everything except "Other"
# the number of bits and the compression modes are fixed
my @rec_modes = ("Chans 1, 2", "Chans 1, 3", "Chans 1 -> 4", "Chans 1 -> 8", "Chans 1, 2, 7, 8",
		 "Chans 3 -> 6","Chans 5 -> 8","Other");
my @number_of_bits = (8, 8, 8, 16, 16, 16, 16, 16);
my @compress_modes = ("ooxx", "oxox", "xxxx", "xxxx", "xxxx", "xxooooxx", "ooxxxxoo","xo");
# Single Recorder, 1 DAS, BW <= 16 MHz
my @single_bw16_rec_modes=("Chan 1","Chan 2","Chan 3","Chan 4",
			   "Chans 1, 2","Chans 1, 3","Chans 3, 4","Chans 2, 4",
			   "Chans 1 -> 4","Other");
my @single_bw16_number_of_bits=(8,8,8,8,8,8,8,8,8,8);
my @single_bw16_compress_modes=("ooox","ooxo","oxoo","xooo","ooxx","oxox",
				"xxoo","xoxo","xxxx","xxxx");
# Single Recorder, 2 DAS, BW <= 16 MHz, Huygen's cable in
my @huygens_bw16_rec_modes=("Chans 1, 5","Chans 2, 6","Chans 3, 7","Chans 4, 8",
			    "Chans 1, 2, 5, 6","Chans 1, 3, 5, 7","Chans 2, 4, 6, 8","Chans 3, 4, 7, 8",
			    "Chans 1, 2, 7, 8","Chans 3, 4, 5, 6","Chans 1 -> 8","Chans 5 -> 8","Other");
push @huygens_bw16_rec_modes,@single_bw16_rec_modes;
my @huygens_bw16_number_of_bits=(16,16,16,16,16,16,16,16,16,16,16,16,16);
push @huygens_bw16_number_of_bits,@single_bw16_number_of_bits;
my @huygens_bw16_compress_modes=("ooox","ooxo","oxoo","xooo","ooxx","oxox","xoxo","xxoo","xxooooxx",
				 "ooxxxxoo","xxxx","xo","xxxx");
push @huygens_bw16_compress_modes,@single_bw16_compress_modes;
# Two Recorders, 2 DAS, BW <= 16 MHz
my @double_bw16_rec_modes=("Chans 1, 5","Chans 3, 7","Chans 1, 2, 5, 6","Chans 3, 4, 7, 8",
			   "Chans 5 -> 8","Chans 1 -> 8","Other");
my @double_bw16_number_of_bits=(8,8,8,8,8,8,8);
my @double_bw16_compress_modes=("ooox","oxoo","ooxx","xxoo","xo","xxxx","xxxx");
# Single Recorder, 1 DAS, BW = 32 MHz
my @single_bw32_rec_modes=("Chan 1","Chan 2","Chans 1, 2","Other");
my @single_bw32_number_of_bits=(8,8,8,8);
my @single_bw32_compress_modes=("ooxx","xxoo","xxxx","xxxx");
# Single Recorder, 2 DAS, BW = 32 MHz, Huygen's cable in
my @huygens_bw32_rec_modes=("Chans 1, 3","Chans 2, 4","Chans 1 -> 4","Chans 5 -> 8","Other");
push @huygens_bw32_rec_modes,@single_bw32_rec_modes;
my @huygens_bw32_number_of_bits=(16,16,16,16,16);
push @huygens_bw32_number_of_bits,@single_bw32_number_of_bits;
my @huygens_bw32_compress_modes=("ooxx","xxoo","xxxx","xo","xxxx");
push @huygens_bw32_compress_modes,@single_bw32_compress_modes;
# Two Recorders, 2 DAS, BW = 32 MHz
my @double_bw32_rec_modes=("Chans 1, 3","Chans 2, 4","Chans 3, 4","Chans 1 -> 4","Other");
my @double_bw32_number_of_bits=(16,16,16,16,16);
my @double_bw32_compress_modes=("ooxx","xxoo","xo","xxxx","xxxx");
# Single Recorder, 1 DAS, BW = 64 MHz
my @single_bw64_rec_modes=("Chan 1","Chan 2","Chans 1, 2","Other");
my @single_bw64_number_of_bits=(8,16,16,16);
my @single_bw64_compress_modes=("xxxx","xo","xxxx","xxxx");
# Two Recorders, 2 DAS, BW = 64 MHz
my @double_bw64_rec_modes=("Chans 1, 3","Chans 2, 4","Chans 1 -> 4","Other");
my @double_bw64_number_of_bits=(8,8,16,16);
my @double_bw64_compress_modes=("xxxx","xo","xxxx","xxxx");

#############################################################################

# defaults
my $rec_mode = $rec_modes[2];
my $nbits = $number_of_bits[2];
my $compress = $compress_modes[2];
my $rate = 256;
my $recording_rate = "";
my $scheduled_start = 0;

# maintain an array which remembers the last $n_pps_remember 1pps OK/not OK results
my $n_pps_remember = 100;
# start warning if the number of missed 1pps in the buffer gets above $n_pps_warn
my $n_pps_warn = 5;
# this variable gets set to 1 if $n_pps_warn is exceeded
my $too_many_missed_pps = 0;
# this value gets set to 1 when the user has acknowledged the problem
my $too_many_missed_pps_msg_started = 0;
# last bugbuf size and %
my $last_bigbuf_free_percent = 0;
my $warned_bigbuf_free_percent = 0;

# this value gets set to 1 when a message describing a problem with
# data files not being written has been sent to the user
my $missed_file_msg_started = 0;
# this value gets set to 1 when a message describing a problem with
# the active disk getting too full has been sent to the user
my $disk_full_msg_started = 0;
# this value gets set to 1 when a message describing a problem with
# bigbuf getting used up has been sent to the user
my $bigbuf_panic_msg_started = 0;

# signals:
my $errorwin_free = 1;
my $start_pps_dialog = 0;
my $start_bigbuf_dialog = 0;
my $start_fulldisk_dialog = 0;
my $start_missing_file_dialog = 0;
my $show_advanced = 0;
my $show_evlbi = 0;
my $show_recorderwin = 0;

# GUI widgets
my $chan_sel_entry;
my $huygens_button;
my ($ut_str, $lst_str, $main, $tv_data_file, $log_t, $comment, $ok_button, $logfile, $advanced, $evlbi);
my ($nbits_entry, $compress_entry);
my ($nbits_label, $compress_label);
my ($start_y, $start_d, $start_h, $start_m, $start_s);
my ($y_e, $d_e, $h_e, $m_e, $s_e, $start_button, $stop_button);
my ($errorwin, $err_msg, $err_frame1);
my ($recorderwin);
my $stats_frame;
my $recsettings_frame;
my $recdisk_frame;
my $uptime_label;
my $recording_status_label;
my $cleaning_status_label;
my $load_experiment_button;
my $unload_experiment_button;
my ($evlbi_nickname,$evlbi_host,$evlbi_port,$evlbi_window,
    $evlbi_button,$evlbi_datagram,$evlbi_selector,$evlbi_remove_button);

my ($record_dur,$record_dur_unit)=(12,"h");
my @record_units=("h","m","s");
my $stats_repeat;
my $sampler_stats="\n\n\n";

# GUI defaults #########################################################
my $font = '*-helvetica-medium-r-*-*-12-*';
my $boldfont = '*-helvetica-bold-r-*-*-12-*';
my $value_bg = 'grey90';
my $fg = 'black';
my $entry_bg = 'white';
my $recording_colour='red';
my $not_recording_colour='orange';
my $pending_recording_colour='yellow';

# GUI status strings
my $tv_last_pps = "";
my $tv_stats = "";
my $tv_last_bigbuf = "";
my $tv_last_block = "";
my $tv_last_filename = "";

my @experiment_available;
my @experiment_loaded;
my $ea_select;
my $el_select;
my $clean_time="12h";
my $is_warning=0;
my $last_warning=0;

my $cfg_server_menu;
my $casc_server;

# global variables

# read configuration file
my $config = Config::Trivial->new(config_file => "$HOME/.disko_config");
my $settings = $config->read;

# get the list of known remote recorders
my @remote_commonname;
my @remote_hostname;
my @remote_datacommunicationport;
my @remote_tcpwindowsize;
my @remote_evlbimode;
my @remote_recorderserverport;
my @remote_udpenabled;
my @remote_ipd;
my @remote_registered;
# we recognise a maximum of 20 remote recorders
for (my $i=1;$i<=20;$i++){
    if ($settings->{"remote_host$i"}){
	$remote_hostname[$i]=$settings->{"remote_host$i"};
	if ($settings->{"remote_common$i"}){
	    $remote_commonname[$i]=$settings->{"remote_common$i"};
	} else {
	    $remote_commonname[$i]=$remote_hostname[$i];
	    $remote_commonname[$i]=~s/(.*?)\..*/$1/;
	}
    } else {
	$remote_hostname[$i]="";
	$remote_commonname[$i]="";
    }
    if ($settings->{"tcp_port$i"}){
	$remote_datacommunicationport[$i]=$settings->{"tcp_port$i"};
    } else {
	$remote_datacommunicationport[$i]=-1;
    }
    if ($settings->{"tcp_window_size$i"}){
	$remote_tcpwindowsize[$i]=$settings->{"tcp_window_size$i"};
    } else {
	$remote_tcpwindowsize[$i]=-1;
    }
    if ($settings->{"evlbi$i"}){
	$remote_evlbimode[$i]=$settings->{"evlbi$i"};
    } else {
	$remote_evlbimode[$i]=0;
    }
    if ($settings->{"recorder_server_port$i"}){
	$remote_recorderserverport[$i]=$settings->{"recorder_server_port$i"};
    } else {
	$remote_recorderserverport[$i]=50080;
    }
    if ($settings->{"udp$i"}){
	$remote_udpenabled[$i]=$settings->{"udp$i"};
    } else {
	$remote_udpenabled[$i]=0;
    }
    if ($settings->{"ipd$i"}){
	$remote_ipd[$i]=$settings->{"ipd$i"};
    }
    $remote_registered[$i]=0;
}

# open the log file
my $at_antenna=$settings->{'antenna'};
if (!defined $at_antenna) {
    warn "No antenna location set. Probably missing from ~/.disko_config\n";
    exit(0);
}
my $log_dir=$settings->{'log_dir'};
if (!defined $log_dir) {
    warn "Output log directory not set. Probably missing from ~/.disko_config\n";
    $log_dir=".";
}
$logfile = sprintf "Disko_%s_%s.log",$at_antenna,get_logfile_timestr();
if (!open_log($log_dir,$logfile)) {
  die "$progname exiting due to problem with the log file\n";
}

# server status variables
my $server_uptime;
my $update_time=10;
my $huygens_cable=0;
my $recorder_status="";
my $cleaner_status;
my $server_manual_mode;
my ($old_yr,$old_doy,$old_hr,$old_min,$old_sec)=(-1,-1,-1,-1,-1);
my $old_sched=-1;
my ($start_command,$stop_command);
my $is_registered=0;
my $is_remote_registered=0;
my $registering=0;
my $get_bitrate=0;

# variables for the available and loaded experiment listboxes
my $available_experiments;
my $loaded_experiments;

my $current_experiment="(manual)";
my $ce_timetoend;
my $next_experiment;
my $ne_timetostart;
my @diskspace_warning;
# $low_space_time is the number of seconds left on a drive
# before the LOW SPACE! warning appears to the right of the
# entry in the drives frame
my $low_space_time=300;
my $disk_space_divider=1;

# get antenna coordinates and convert to lat, long
my $recorders=$settings->{'server'};
if (!defined $recorders) {
    warn "Recorders not set. Probably missing from ~/.disko_config\n";
    exit(0);
}
my @rec_servers=split(/\s+/,$recorders);
my $current_recorder=$rec_servers[0];
my $nrecorders=$#rec_servers;
my @recorder_active;
my @recorder_ip;
for (my $i=0;$i<=$#rec_servers;$i++){
    $recorder_active[$i]=1;
    my @name_els=split(":",$rec_servers[$i]);
    my ($name,$aliases,$addrtype,$length,@addrs) = gethostbyname($name_els[0]);

    # Check resolved name OK
    die "Could not resolve $name_els[0]\n" if (! defined $name);

    my ($a,$b,$c,$d) = unpack('C4',$addrs[0]);
    $recorder_ip[$i]="$a.$b.$c.$d";
}
my @ant_coord = @{$Antennas{$settings->{'antenna'}}};

my ($long_turns, $lat_turns) = Astro::Coord::r2pol(@ant_coord);
my $lat_deg = $lat_turns*360.0;
my $long_deg = $long_turns*360.0;
if ($debug) {
  print "lat = $lat_deg, long = $long_deg\n";
}


# get data directories and calculate capacity of each one
my $in_startup=1;

my $active_disk;
my @disk_label;
my @disk_avail;
my @disk_total;
my @disk_perc_free;
my @disk_time_left;

my $read_file;

# set up a child reaper
$SIG{CHLD}  = sub { wait; };
my $cpid;
my $tpid;
if (!($cpid=fork)){ # child
    $SIG{CHLD} = 'IGNORE';
    open STDOUT, ">/tmp/server_messages";# or die "Can't redirect STDOUT: $!";
    exec "server_listener" or die "unable to launch listener";
} else {
    sleep(1);
    $tpid=open($read_file,"tail -f /tmp/server_messages|");
}	

my @data_disks;
my @data_recorders;
my ($rec_recorder,$rec_disk,$rec_label,$rec_total,$rec_avail,$rec_perc_free,
    $rec_timeleft)=("","","","","","","");

$Current_Parameters{"remote_commonname"}="";
$Current_Parameters{"remote_host"}="";
$Current_Parameters{"tcp_port"}="";
$Current_Parameters{"tcp_window_size"}="";

&get_start_ydhms();
&first_update();

$in_startup=0;

$main->fileevent($read_file,'readable' => \&received_message);
&MainLoop();

sub update_routine {
    # first we see what has changed from previously
    my $changed;
    my @all_changed;

    for (my $i=0;$i<=$#settable_parameters;$i++){
	$changed=0;
	if ($settable_types[$i] eq "string"){
	    if ($Current_Parameters{$settable_parameters[$i]} ne 
		$Old_Parameters{$settable_parameters[$i]}){
		$changed=1;
	    }
	} elsif ($settable_types[$i] eq "number"){
	    if ($Current_Parameters{$settable_parameters[$i]}!=
		$Old_Parameters{$settable_parameters[$i]}){
		$changed=1;
	    }
	}
	if ($changed==1){
	    push @all_changed,$settable_parameters[$i];
	} elsif ($set_all_remote_options==1){
	    for (my $j=0;$j<=$#remote_settable_parameters;$j++){
		if ($settable_parameters[$i] eq $remote_settable_parameters[$j]){
		    if ((($settable_parameters[$i] eq "fringecheck_flag")&&
			($fringecheck_already_set==0))||
			($settable_parameters[$i] ne "fringecheck_flag")){
			push @all_changed,$settable_parameters[$i];
		    }
		}
	    }
	}
    }

    # do what needs to be done for the changed parameters
    for (my $i=0;$i<=$#all_changed;$i++){
	if ($all_changed[$i] eq "experiment_name"){
	    # change the directory and filename prefix
	    my $new_experiment_name=$Current_Parameters{$all_changed[$i]};
	    my $dir_name=$new_experiment_name;
	    my $file_name="$new_experiment_name\_$Antenna_abbrev{$at_antenna}";
	    logit_blue("Setting experiment name to $new_experiment_name\n");
	    # for eVLBI we need to set the directory name on the remote
	    # machine, and the filename on the local machine
	    my $comm_result;
	    $comm_result=&server_comms("data","directory_name=$dir_name");
	    if (&success($comm_result)){
		$comm_result=&server_comms("data","filename_prefix=$file_name");
		if (&success($comm_result)){
		    logit_green("Experiment name successfully set.\n");
		} else {
		    logit_red("Unable to set experiment name: $communication_error\n");
		    my $old_experiment_name=$Old_Parameters{$all_changed[$i]};
		    $comm_result=&server_comms("data","directory_name=$old_experiment_name");
		}
	    } else {
		logit_red("Unable to set experiment name: $communication_error\n");
		$Current_Parameters{$all_changed[$i]}=$Old_Parameters{$all_changed[$i]};
	    }
	} elsif ($all_changed[$i] eq "fringecheck_flag"){
	    # enable/disable the fringe check flag
	    my $set_ft;
	    if ($Current_Parameters{$all_changed[$i]}==1){
		# enable
		$set_ft="yes";
	    } elsif ($Current_Parameters{$all_changed[$i]}==0){
		# disable
		$set_ft="no";
	    }
	    logit_blue("Setting fringe-check flag.\n");
	    my $comm_result;
	    $comm_result=&server_comms("data","fringetest=$set_ft");
	    if (&success($comm_result)){
		logit_green("Fringe-check flag successfully set.\n");
	    } else {
		logit_red("Unable to set fringe-check flag: $communication_error\n");
		$Current_Parameters{$all_changed[$i]}=$Old_Parameters{$all_changed[$i]};
	    }
	    if ($set_ft eq "no"){
		# now we have to set the experiment name again
		$Old_Parameters{"experiment_name"}="";
		$Old_Parameters{"fringecheck_flag"}=0;
		$fringecheck_already_set=1;
		&update_routine;
	    }
	} elsif ($all_changed[$i] eq "bandwidth"){
	    # change the bandwidth
	    $get_bitrate=1; # this will affect the bitrate
	    my $new_bandwidth=$Current_Parameters{$all_changed[$i]};
	    logit_blue("Setting bandwidth to $new_bandwidth\n");
	    my $comm_result=&server_comms("data","bandwidth=$new_bandwidth");
	    if (&success($comm_result)){
		logit_green("Bandwidth successfully set.\n");
	    } else {
		logit_red("Unable to set bandwidth: $communication_error\n");
		$Current_Parameters{$all_changed[$i]}=$Old_Parameters{$all_changed[$i]};
	    }
	} elsif ($all_changed[$i] eq "compression"){
	    # change the compression
	    $get_bitrate=1; # this will affect the bitrate
	    my $new_compression=$Current_Parameters{$all_changed[$i]};
	    logit_blue("Setting compression to $new_compression\n");
	    my $comm_result=&server_comms("data","compression=$new_compression");
	    if (&success($comm_result)){
		logit_green("Compression successfully set.\n");
	    } else {
		logit_red("Unable to set compression: $communication_error\n");
		$Current_Parameters{$all_changed[$i]}=$Old_Parameters{$all_changed[$i]};
	    }
	} elsif ($all_changed[$i] eq "vsib_bits"){
	    # change the VSIB mode
	    $get_bitrate=1; # this will affect the bitrate
	    my $new_vsib_mode;
	    if ($Current_Parameters{$all_changed[$i]}==8){
		$new_vsib_mode=3;
	    } elsif ($Current_Parameters{$all_changed[$i]}==16){
		$new_vsib_mode=2;
	    }
	    logit_blue("Setting VSIB mode to $new_vsib_mode\n");
	    my $comm_result=&server_comms("data","vsib_mode=$new_vsib_mode");
	    if (&success($comm_result)){
		logit_green("VSIB mode successfully set.\n");
	    } else {
		logit_red("Unable to set VSIB mode: $communication_error\n");
		$Current_Parameters{$all_changed[$i]}=$Old_Parameters{$all_changed[$i]};
	    }
	} elsif (($all_changed[$i] eq "record_duration")||
		 ($all_changed[$i] eq "duration_unit")){
	    # change the recording time
	    my $new_record_duration=$Current_Parameters{"record_duration"};
	    my $new_duration_unit=$Current_Parameters{"duration_unit"};
	    my $new_record_time="$new_record_duration$new_duration_unit";
	    logit_blue("Setting recording time to $new_record_time\n");
	    my $comm_result=&server_comms("data","record_time=$new_record_time");
	    if (&success($comm_result)){
		logit_green("Recording time successfully set.\n");
		# special case - to stop the time being updated twice
		# when both the duration number and unit have changed in
		# a single update, we get rid of the other $all_changed
		# entry
		for (my $j=$i+1;$j<=$#all_changed;$j++){
		    if (($all_changed[$j] eq "record_duration")||
			($all_changed[$j] eq "duration_unit")){
			$all_changed[$j]="";
			last;
		    }
		}
	    } else {
		logit_red("Unable to set recording time: $communication_error\n");
		$Current_Parameters{"record_duration"}=$Old_Parameters{"record_duration"};
		$Current_Parameters{"duration_unit"}=$Old_Parameters{"duration_unit"};
	    }
	} elsif ($all_changed[$i] eq "active_disk"){
	    # change the output disk
	    my $new_active_disk=$Current_Parameters{$all_changed[$i]};
	    logit_blue("Setting active disk to $new_active_disk\n");
	    my $comm_result;
	    $new_active_disk=~s/^local\://;
	    $new_active_disk=~s/eVLBI//;
	    $comm_result=&server_comms("data","recordingdisk=$new_active_disk");
	    if (&success($comm_result)){
		logit_green("Active disk set succesfully.\n");
	    } else {
		logit_red("Unable to set active disk: $communication_error\n");
		$Current_Parameters{$all_changed[$i]}=$Old_Parameters{$all_changed[$i]};
	    }
	} elsif ($all_changed[$i] eq "auto_experiment"){
	    # change the server behaviour when starting
	    # scheduled experiments
	    my $new_auto_experiment;
	    if ($Current_Parameters{$all_changed[$i]}==1){
		# make the server automatically start
		# experiments when they are scheduled
		$new_auto_experiment="on";
	    } elsif ($Current_Parameters{$all_changed[$i]}==0){
		# make the server wait for the command
		# to start an experiment from the user
		$new_auto_experiment="off";
	    }
	    logit_blue("Turning auto experiment execution $new_auto_experiment.\n");
	    my $comm_result=&server_comms("data","experimentexecute=$new_auto_experiment");
	    if (&success($comm_result)){
		logit_green("Auto experiment execution successfully set.\n");
	    } else {
		logit_red("Unable to set auto experiment execution: $communication_error\n");
		$Current_Parameters{$all_changed[$i]}=$Old_Parameters{$all_changed[$i]};
	    }
	} elsif ($all_changed[$i] eq "auto_rounding"){
	    # change the recorder behaviour when starting
	    # a recording
	    my $new_auto_rounding;
	    if ($Current_Parameters{$all_changed[$i]}==1){
		# make the recorder start recording at
		# an integer block boundary
		$new_auto_rounding="on";
	    } elsif ($Current_Parameters{$all_changed[$i]}==0){
		# make the recorder start immediately
		$new_auto_rounding="off";
	    }
	    logit_blue("Turning start rounding $new_auto_rounding.\n");
	    my $comm_result=&server_comms("data","round_start=$new_auto_rounding");
	    if (&success($comm_result)){
		logit_green("Start rounding successfully set.\n");
	    } else {
		logit_red("Unable to set start rounding: $communication_error\n");
		$Current_Parameters{$all_changed[$i]}=$Old_Parameters{$all_changed[$i]};
	    }
#	} elsif ($all_changed[$i] eq "clean_time"){
#	    # set or unset the auto cleaning function of
#	    # the server
#	    my $new_clean_time;
#	    if ($Current_Parameters{$all_changed[$i]} eq ""){
#		# unset the cleaning time, using the variable
#		# reset instruction
#		$new_clean_time="reset=cleantime";
#		logit_blue("Resetting cleaning time.\n");
#	    } else {
#		# change the cleaning time
#		$new_clean_time="cleantime=$Current_Parameters{$all_changed[$i]}";
#		logit_blue("Setting cleaning time to $new_clean_time.\n");
#	    }
#	    my $comm_result=&server_comms("data","$new_clean_time");
#	    if (&success($comm_result)){
#		logit_green("Cleaning time successfully set.\n");
#	    } else {
#		logit_red("Unable to set cleaning time: $communication_error\n");
#		$Current_Parameters{$all_changed[$i]}=$Old_Parameters{$all_changed[$i]};
#	    }
	} elsif ($all_changed[$i] eq "vsib_device"){
	    # specify the location of the VSIB recorder
	    # device file
	    my $new_vsib_location=$Current_Parameters{$all_changed[$i]};
	    logit_blue("Setting VSIB device file location to $new_vsib_location.\n");
	    my $comm_result=&server_comms("data","vsib_device=$new_vsib_location");
	    if (&success($comm_result)){
		logit_green("VSIB device file location successfully set.\n");
	    } else {
		logit_red("Unable to set VSIB device file location: $communication_error\n");
		$Current_Parameters{$all_changed[$i]}=$Old_Parameters{$all_changed[$i]};
	    }
	} elsif ($all_changed[$i] eq "file_size"){
	    # specify the new recorder file size
	    my $new_filesize=$Current_Parameters{$all_changed[$i]};
	    logit_blue("Setting output file size to $new_filesize.\n");
	    my $comm_result=&server_comms("data","filesize=$new_filesize");
	    if (&success($comm_result)){
		logit_green("Output file size successfully set.\n");
	    } else {
		logit_red("Unable to set output file size: $communication_error\n");
		$Current_Parameters{$all_changed[$i]}=$Old_Parameters{$all_changed[$i]};
	    }
	} elsif ($all_changed[$i] eq "block_size"){
	    my $new_blocksize=$Current_Parameters{$all_changed[$i]};
	    logit_blue("Setting recorder block size to $new_blocksize.\n");
	    my $comm_result=&server_comms("data","blocksize=$new_blocksize");
	    if (&success($comm_result)){
		logit_green("Recorder block size successfully set.\n");
	    } else {
		logit_red("Unable to set recorder block size: $communication_error\n");
		$Current_Parameters{$all_changed[$i]}=$Old_Parameters{$all_changed[$i]};
	    }
	} elsif ($all_changed[$i] eq "clock_rate"){
	    my $new_clockrate=$Current_Parameters{$all_changed[$i]};
	    logit_blue("Setting VSIB clock rate to $new_clockrate.\n");
	    my $comm_result=&server_comms("data","clockrate=$new_clockrate");
	    if (&success($comm_result)){
		logit_green("VSIB clock rate successfully set.\n");
	    } else {
		logit_red("Unable to set VSIB clock rate: $communication_error\n");
		$Current_Parameters{$all_changed[$i]}=$Old_Parameters{$all_changed[$i]};
	    }
	} elsif ($all_changed[$i] eq "mark5b"){
	    my $new_mark5b;
	    if ($Current_Parameters{$all_changed[$i]}==1){
		# enable recording in Mark5B style
		$new_mark5b="on";
	    } elsif ($Current_Parameters{$all_changed[$i]}==0){
		# enable default LBA recording style
		$new_mark5b="off";
	    }
	    logit_blue("Turning Mark5B style recording $new_mark5b.\n");
	    my $comm_result=&server_comms("data","mark5b=$new_mark5b");
	    if (&success($comm_result)){
		logit_green("Recording style successfully set.\n");
	    } else {
		logit_red("Unable to set recording style: $communication_error\n");
		$Current_Parameters{$all_changed[$i]}=$Old_Parameters{$all_changed[$i]};
	    }
	}
    }
}

sub update_server {
    # we just tell the server about any changed variables in
    # this routine
    $fringecheck_already_set=0;
    $get_bitrate=0;
    &update_routine;
    $set_all_remote_options=0;
    $fringecheck_already_set=0;
    if ($get_bitrate==1){
	# now get the settings that the server has
	&contact_server();
	
	for (my $i=0;$i<=$#settable_parameters;$i++){
	    $Current_Parameters{$settable_parameters[$i]}=&get_param($settable_parameters[$i]);
	}
	if ($recorder_status ne "Not recording"){
	    for (my $i=0;$i<=$#settable_parameters;$i++){
		$Current_Parameters{"rs_$settable_parameters[$i]"}=&get_param("rs_$settable_parameters[$i]");
	    }
	}
	
	%Old_Parameters=%Current_Parameters;
	&get_others();
    }

    # make sure the GUI is consistent with itself
    &set_mode_options();
    &set_record_mode();
    &remotehost_display();

    %Old_Parameters=%Current_Parameters;
}

sub server_update {
    # keep the log window clean by removing text if the log gets too long
    $log_t->delete('0.0','end - 1000 lines');
    # we check everything in this routine, and contact the server
    &register_client();
    &update_routine;

    # now get the settings that the server has
    &contact_server();

    # change the title of the recorder status window depending on recording status
    if ($recorder_status eq "Not recording"){
	$recorderwin->title("Recording Information - Last Recording");
    } else {
	$recorderwin->title("Recording Information - Current Recording");
    }

    for (my $i=0;$i<=$#settable_parameters;$i++){
	$Current_Parameters{$settable_parameters[$i]}=&get_param($settable_parameters[$i]);
    }
    if ($recorder_status ne "Not recording"){
	for (my $i=0;$i<=$#settable_parameters;$i++){
	    $Current_Parameters{"rs_$settable_parameters[$i]"}=&get_param("rs_$settable_parameters[$i]");
	    if ($Current_Parameters{"rs_$settable_parameters[$i]"} eq ""){
		# keep the last settings from the previous recording
		$Current_Parameters{"rs_$settable_parameters[$i]"}=$Old_Parameters{"rs_$settable_parameters[$i]"};
	    }
	}
	# change the labels to match the current recording disk
	for (my $r=0;$r<=$#data_disks;$r++){
	    if ($Current_Parameters{"rs_active_disk"} eq "$data_recorders[$r]:$data_disks[$r]"){
		$rec_recorder=$data_recorders[$r];
		$rec_disk=$data_disks[$r];
		$rec_label=$disk_label[$r];
		$rec_total=$disk_total[$r];
		$rec_avail=$disk_avail[$r];
		$rec_perc_free=$disk_perc_free[$r];
		last;
	    }
	}
    } else {
	for (my $i=0;$i<=$#settable_parameters;$i++){
	    # keep the last settings from the previous recording
	    $Current_Parameters{"rs_$settable_parameters[$i]"}=$Old_Parameters{"rs_$settable_parameters[$i]"};
	}
    }

    %Old_Parameters=%Current_Parameters;
    &get_others();

    # make sure the GUI is consistent with itself
    &set_mode_options();
    &set_record_mode();
    &remotehost_display();
}

sub success {
    # check for the success flag from a communication with the
    # recorder server, and if return 1 if we find it.
    # otherwise, an error has occurred and we return 0 and set
    # the global variable $communication_error to the failure
    # message
    my $check_communication = $_[0];
    my $retval=1;
    if ($check_communication=~/\<succ\s\/\>/){
	# communication was successful
	$communication_error="";
	$retval=1;
    } elsif ($check_communication=~/^\<fail\>/) {
	# there was a failure code
	$communication_error=&strip_fail($check_communication);
	$retval=0;
    }
    $retval;
}

sub register_client {
    # we register the machine that cDisko is running on
    # as a message client, so that the recorder server
    # will send us recorder status and error messages
    # automatically
    if ($is_registered==0){
	# needs to be registered
	$registering=1; # main host
	my $comm_result=&server_comms("cmnd","client-register");
	# the server may report that it has sent the
	# registration message, but that doesn't mean
	# anything - we need the listener to report back
	# and say it responded - another routine will
	# handle this
    }
}

sub first_update {
    # contact the server
    &register_client();
    &contact_server();
    if (length($server_response)==0){
	die("unable to contact server! exiting.\n");
    }

    &get_available_disks($server_response);
    $active_disk = $data_disks[0];

    # set up the Current_Parameters structure
    for (my $i=0;$i<=$#settable_parameters;$i++){
	$Current_Parameters { $settable_parameters[$i] } = &get_param($settable_parameters[$i]);
    }
    %Old_Parameters=%Current_Parameters;

    # ready to start the GUI now
    &init_gui();

    $in_startup=0;
    &get_others();

    # make sure the GUI is consistent with itself
    &set_mode_options();
    &set_record_mode();
    &remotehost_display();
}

sub get_available_disks {
    my $response_from_server=$_[0];
    # get the available disks
    $settings->{'disks'}="";
    $settings->{'recorders'}="";
    my @response_split=split(/\n/,$response_from_server);
    my $look_for_disks=1;
#    if ($Current_Parameters{"disks_displayed"} eq "REMOTE"){
#	$look_for_disks=0;
#    }
    for (my $i=0;$i<=$#response_split;$i++){
	if (($response_split[$i]=~/\s\sdisk\s/)&&
	    ($look_for_disks==1)){
	    # disk line in the server status string
	    my @els=split(/\s+/,$response_split[$i]);
	    my ($thisrecorder,$thisdisk);
	    if ($response_split[$i]=~/eVLBI\srecorder/){
		$els[2]=~s/[\[\]\:]//g;
		$thisrecorder=$els[2];
		$thisdisk=$els[3];
	    } else {
		$els[3]=~s/[\[\]]//g;
		$els[3]=~s/\:$//g;
		if ($els[3]=~/\:/){
		    $thisrecorder=$els[3];
		    $thisrecorder=~s/(.*)\:.*/$1/;
		    $thisdisk=$els[3];
		    $thisdisk=~s/.*\:(.*)/$1/;
		} else {
		    $thisdisk=$els[3];
		    $thisrecorder="local";
		}
	    }
	    if ($settings->{'disks'} eq ""){
		$settings->{'disks'}="$thisdisk";
		$settings->{'recorders'}="$thisrecorder";
	    } else {
		$settings->{'disks'}="$settings->{'disks'} $thisdisk";
		$settings->{'recorders'}="$settings->{'recorders'} $thisrecorder";
	    }
	} elsif ($response_split[$i] eq "REMOTE_FOLLOWS"){
	    $look_for_disks=1;
	}
    }
    @data_disks=split(/\s+/,$settings->{'disks'});
    @data_recorders=split(/\s+/,$settings->{'recorders'});
}

sub contact_server {
    # get all the info we can from the server and stick it
    # into a long string, $server_response
    my $comm_result;
    $server_response="";
    for (my $i=0;$i<=$#info_commands;$i++){
	$server_response="$server_response\n$info_commands[$i]";
	for (my $j=1;$j<=$n_retries;$j++){
	    $comm_result=&server_comms("cmnd",$info_commands[$i]);
	    if ($comm_result eq "Can't connect to socket"){
		# oh dear, we can't connect to the server
		if ($j==$n_retries){
		    $server_uptime="DOWN";
		    logit_red("Could not contact server!\n");
		    $is_registered=0;
		}
	    } elsif ($comm_result!~/\<fail\>/) {
		$server_response="$server_response\n$comm_result";
		last;
	    }
	}
    }
}

sub get_others {
    # go through the server response string and determine
    # the values of stuff that can't be set by the user
    $sampler_stats="";
    $tv_last_pps="";
    $tv_stats="";
    $tv_last_bigbuf="";
    $tv_last_block="";
    my @response_split=split(/\n/,$server_response);
    my $in_remote=0;
    my $ndisksfound=0;
    my $command_next=0;
    for (my $i=0;$i<=$#response_split;$i++){
	if (($response_split[$i]=~/Current\ssettings/)&&
	    ($in_remote==0)){
	    # get the recording rate
	    my $rec_rate=$response_split[$i];
	    $rec_rate=~s/^.*BR\=(.*)$/$1/;
	    $rate=$rec_rate;
	} elsif ($response_split[$i]=~/Current\srecording\ssettings/){
	    my $rec_rate=$response_split[$i];
	    $rec_rate=~s/^.*BR\=(.*)$/$1/;
	    $recording_rate=$rec_rate;
	} elsif (($response_split[$i]=~/Server\suptime/)&&
		 ($in_remote==0)){
	    # get the server uptime
	    my $uptime_server=$response_split[$i];
	    $uptime_server=~s/^.*\:\s(.*)$/$1/;
	    $server_uptime=$uptime_server;
	} elsif ($response_split[$i]=~/\s*disk\s+(\d+)\s+\[(\S+)\s+\"([^\"]*)\"\]:\s*
	       TOTAL:\s+(\S+)\s+MB\s+
	       FREE:\s+(\S+)\s+MB\s+\((\S+)\%\)\s+
	       TIME:\s+(\S+)\s*(\S*)
		 /x){
	    # get info about a disk
	    $ndisksfound++;
	    for (my $j=0;$j<=$#data_disks;$j++){
		if (($2 eq $data_disks[$j])||
		    ($2 eq $data_recorders[$j].":".$data_disks[$j])){
		    $disk_label[$j]=$3;
		    my $time_avail_seconds;
		    my $space_unit;
		    if ($4<=100){
			$disk_space_divider=1;
			$space_unit="M";
			$disk_avail[$j]=sprintf "%d%s",$5/$disk_space_divider,$space_unit;
		    } else {
			$disk_space_divider=1024;
			$space_unit="G";
			$disk_avail[$j]=sprintf "%.1f%s",$5/$disk_space_divider,$space_unit;
		    }
		    if ($4<=100){
			$disk_space_divider=1;
			$space_unit="M";
			$disk_total[$j]=sprintf "%d%s",$4/$disk_space_divider,$space_unit;
		    } else {
			$disk_space_divider=1024;
			$space_unit="G";
			$disk_total[$j]=sprintf "%.1f%s",$4/$disk_space_divider,$space_unit;
		    }
		    #$els[11]=~s/[\(\)]//g;
		    $disk_perc_free[$j]=$6;
		    my ($avail_days,$avail_hours,$avail_minutes,$avail_seconds);
		    my $t7=$7;
		    my $t8=$8;
		    if ($t7=~/d$/){
			$disk_time_left[$j]="$t7 $t8";
			$avail_days=$t7;
			$avail_days=~s/d//;
			($avail_hours,$avail_minutes,$avail_seconds)=split(":",$t8);
		    } else {
			$disk_time_left[$j]=$t7;
			$avail_days=0;
			($avail_hours,$avail_minutes,$avail_seconds)=split(":",$t7);
		    }
		    $time_avail_seconds=$avail_days*86400+$avail_hours*3600+
			$avail_minutes*60+$avail_seconds;
		    if ($time_avail_seconds<=$low_space_time){
			# make the red LOW SPACE warning show up
			$diskspace_warning[$j]->configure(-foreground => 'red');
		    } else {
			# hide the red LOW SPACE warning
			$diskspace_warning[$j]->configure(-foreground => $value_bg);
		    }
		}
	    }
	} elsif (($response_split[$i]=~/Current\sExperiment/)&&
		 ($in_remote==0)){
	    # the currently scheduled experiment
	    my $experiment_current=$response_split[$i];
	    $experiment_current=~s/^.*\:\s*(.*)$/$1/;
	    $current_experiment=$experiment_current;
	    if ($experiment_current=~/.*\(manual\).*/){
		# it isn't from an experiment profile
		$server_manual_mode=1;
	    } else {
		# it is from an experiment profile
		$server_manual_mode=0;
	    }
	} elsif (($response_split[$i]=~/Time\suntil\send/)&&
		 ($in_remote==0)){
	    # the time until the currently scheduled
	    # experiment finishes
	    my @els=split(/\s+/,$response_split[$i]);
	    $ce_timetoend="";
	    for (my $j=3;$j<=$#els;$j++){
		$ce_timetoend="$ce_timetoend $els[$j]";
	    }
	    $ce_timetoend=~s/^\s*//;
	} elsif (($response_split[$i]=~/Next\sExperiment/)&&
		 ($in_remote==0)){
	    # the next scheduled experiment
	    my $experiment_next=$response_split[$i];
	    $experiment_next=~s/^.*\:\s*(.*)$/$1/;
	    $next_experiment=$experiment_next;
	} elsif (($response_split[$i]=~/Time\suntil\sstart/)&&
		 ($in_remote==0)){
	    # the time until the next scheduled
	    # experiment starts
	    my @els=split(/\s+/,$response_split[$i]);
	    $ne_timetostart="";
	    for (my $j=3;$j<=$#els;$j++){
		$ne_timetostart="$ne_timetostart $els[$j]";
	    }
	    $ne_timetostart=~s/^\s*//;
	} elsif (($response_split[$i]=~/Recording\sStatus/)&&
		 ($in_remote==0)){
	    # quick version of the recorder status
	    # just "recording" or "not recording"
	    my $status_recorder=$response_split[$i];
	    $status_recorder=~s/^.*\:\s*(.*)$/$1/;
	    $status_recorder=~s/\.$//;
	    $recorder_status=$status_recorder;
	    if ($recorder_status eq "Not recording"){
		$recording_status_label->configure(-background => $not_recording_colour);
		$main->title("$progname v$progvers");
		$main->iconname("$progname");
	    } else {
		$recording_status_label->configure(-background => $recording_colour);
		$main->title("$progname v$progvers - RECORDING");
		$main->iconname("$progname - RECORDING");
	    }
	} elsif (($response_split[$i]=~/Recording\swill\sbegin\sin/)&&
		 ($in_remote==0)){
	    # the recording hasn't started yet, but vsib_record has
	    $recorder_status="Recording Pending";
	    $recording_status_label->configure(-background => $pending_recording_colour);
#	} elsif (($response_split[$i]=~/Cleaning\sStatus/)&&
#		 ($in_remote==0)){
#	    # the number of cleaners currently running
#	    my $status_cleaner=$response_split[$i];
#	    $status_cleaner=~s/^.*\:\s*(.*)$/$1/;
#	    $status_cleaner=~s/\.$//;
#	    $cleaner_status=$status_cleaner;
#	    if ($cleaner_status=~/No\scleaners\srunning/){
#		$cleaning_status_label->configure(-background => $not_recording_colour);
#	    } else {
#		$cleaning_status_label->configure(-background => $recording_colour);
#	    }
	} elsif (($response_split[$i]=~/available\sexperiment\sprofiles/)&&
		 ($in_remote==0)){
	    # the experiment profiles on disk
	    my @new_available_experiments;
	    for (my $j=$i+1;$j<=$#response_split;$j++){
		if (length($response_split[$j])>0){
		    if ($response_split[$j] ne "(none)"){
			push @new_available_experiments,$response_split[$j];
		    }
		} else {
		    last;
		}
	    }
	    @experiment_available=@new_available_experiments;
	} elsif (($response_split[$i]=~/loaded\sexperiment\sprofiles/)&&
		 ($in_remote==0)){
	    # the experiment profiles in the queue
	    my @new_loaded_experiments;
	    for (my $j=$i+1;$j<=$#response_split;$j++){
		if (length($response_split[$j])>0){
		    if ($response_split[$j] ne "(none)"){
			push @new_loaded_experiments,$response_split[$j];
		    } else {
			last;
		    }
		} else {
		    last;
		}
	    }
	    @experiment_loaded=@new_loaded_experiments;
	    # now remove from the available list the experiments
	    # which are already loaded
	    my @old_available_experiments=@experiment_available;
	    my @new_available_experiments;
	    for (my $j=0;$j<=$#old_available_experiments;$j++){
		for (my $k=0;$k<=$#experiment_loaded;$k++){
		    if ($old_available_experiments[$j] eq $experiment_loaded[$k]){
			$old_available_experiments[$j]="a/l";
			last;
		    }
		}
		if ($old_available_experiments[$j] ne "a/l"){
		    push @new_available_experiments,$old_available_experiments[$j];
		}
	    }
	    @experiment_available=@new_available_experiments;
	    # reassign the combobox contents
	    $available_experiments->configure(-choices => \@experiment_available,
					      -listheight => ($#experiment_available+1));
	    $loaded_experiments->configure(-choices => \@experiment_loaded,
					   -listheight => ($#experiment_loaded+1));
	} elsif (($response_split[$i]=~/last\sfile\sopened\sat/)&&
		 ($in_remote==0)){
	    # the last opened block number
	    my @lels=split(/\s+/,$response_split[$i]);
	    $tv_last_block=$lels[$#lels-1];
	    # the last opened file
	    $tv_last_filename=$lels[$#lels];
	    $tv_last_filename=~s/[\(\)]//g;
	} elsif (($response_split[$i]=~/BIGBUF\sfree/)&&
		 ($in_remote==0)){
	    # the last BIGBUF memory free amount
	    my $last_bigbuf_tv=$response_split[$i];
	    $last_bigbuf_tv=~s/^.*\=\s(\d*)\sMB\s\((\d*)\%\).*$/$1 ($2\%)/;
	    $tv_last_bigbuf=$last_bigbuf_tv;
	} elsif (($response_split[$i]=~/PPS\ssignal\sOK/)&&
		 ($in_remote==0)){
	    # the last PPS was received OK
	    $tv_last_pps="OK";
	} elsif (($response_split[$i]=~/1PPS/)&&
		 ($in_remote==0)){
	    # the last PPS was missed
	    $tv_last_pps="Missed";
	} elsif (($response_split[$i]=~/^PPS\smissed/)&&
		 ($in_remote==0)){
	    # the history of PPS misses
	    my @sels=split(/\s+/,$response_split[$i]);
	    $tv_stats="$sels[2] from last $sels[6]";
	} elsif (($response_split[$i]=~/^Chan\s\d/)&&
		 ($in_remote==0)){
	    # a line of the sampler statistics
	    $sampler_stats="$sampler_stats\n$response_split[$i]";
	    $sampler_stats=~s/^\n//;
	} elsif ($response_split[$i]=~/^recording\sto\sdisk/){
	    my $which_disk_records=$response_split[$i];
	    $which_disk_records=~s/^recording\sto\sdisk\s(.*)\s\(.*\), path .*/$1/;
	    $recording_to_disk=-1;
	    for (my $r=0;$r<=$#data_disks;$r++){
		if ($data_disks[$r] eq $which_disk_records){
		    $recording_to_disk=$r;
		}
	    }
	} elsif ($response_split[$i]=~/^No\sremote\srecorders\shave\sbeen\sspecified\.*/){
	    # no remote hosts are known to the recorder, so we disable
	    # all the ones we have here
	    for (my $j=1;$j<=$#remote_commonname;$j++){
		if ($remote_commonname[$j] ne ""){
		    $remote_registered[$j]=0;
		}
	    }
	} elsif ($response_split[$i]=~/^Remote\srecorder.*/){
	    # a remote host is known
	    my $foundhost=$response_split[$i];
	    $foundhost=~s/.*?\"(.*)\"\:/$1/;
	    for (my $j=1;$j<=$#remote_commonname;$j++){
		if ($foundhost eq $remote_commonname[$j]){
		    $remote_registered[$j]=1;
		}
	    }
	} elsif (($response_split[$i]=~/^Recorder\sprocess\srunning\./)&&
		 ($get_recorder_command==1)){
	    $command_next=1;
	    $get_recorder_command=0;
	} elsif ($command_next==1){
	    logit("Recorder started with command:\n");
	    logit($response_split[$i]."\n");
	    $command_next=0;
	}
    }
    if ($last_num_disks==-1){
	$last_num_disks=$ndisksfound;
    } else {
	if ($ndisksfound!=$last_num_disks){
	    &change_disks();
	    $last_num_disks=$ndisksfound;
	}
    }

}

sub get_param {
    # go through the server response string and determine
    # the value of the parameter the user wants
    my $look_for_param = $_[0];
    my $look_for_rs=0;
    if ($look_for_param=~/^rs\_/){
	# we're looking for a setting for the current recording
	$look_for_param=~s/^rs\_//;
	$look_for_rs=1;
    }
    my $retval="";
    my $holdvalue="";
    my $recsettings=0;

    my @response_split=split(/\n/,$server_response);
    for (my $i=0;$i<=$#response_split;$i++){
	if ($response_split[$i]=~/\sTarget\srecorder/){
	    $holdvalue=$response_split[$i];
	    $holdvalue=~s/^.*\:\s*(.*)$/$1/;
	} elsif ($response_split[$i]=~/status\-recsettings/){
	    $recsettings=1;
	}
	if (($response_split[$i]=~/\sOutput\sdirectory/)&&
	    ($look_for_param eq "experiment_name")&&
	    ((($look_for_rs==0)&&($Current_Parameters{"fringecheck_flag"}==0))||
	     (($look_for_rs==1)&&($Current_Parameters{"rs_fringecheck_flag"} eq "N")))&&
	    ($recsettings==$look_for_rs)){
	    # get the experiment name if the experiment is not
	    # a fringe test, so we just copy the name of the
	    # directory
	    $retval=$response_split[$i];
	    $retval=~s/^.*\:\s*(.*)$/$1/;
	    if ($retval eq "not set"){
		$retval="";
	    }
	} elsif (($response_split[$i]=~/\sFilename\sprefix/)&&
		 ($look_for_param eq "experiment_name")&&
		 ((($look_for_rs==0)&&($Current_Parameters{"fringecheck_flag"}==1))||
		  (($look_for_rs==1)&&($Current_Parameters{"rs_fringecheck_flag"} eq "Y")))&&
		 ($recsettings==$look_for_rs)){
	    # get the experiment name if the experiment is a
	    # fringe test - we copy the prefix of the files,
	    # leaving off any station subscript if it's there
	    $retval=$response_split[$i];
	    $retval=~s/^.*\:\s*(.*)$/$1/;
	    if (substr($retval,-3) eq "_$Antenna_abbrev{$at_antenna}"){
		$retval=substr($retval,0,-3);
	    }
	    if ($retval eq "not set"){
		$retval="";
	    }
	} elsif (($response_split[$i]=~/\sBandwidth/)&&
		 ($look_for_param eq "bandwidth")&&
		 ($recsettings==$look_for_rs)){
	    # get the bandwidth
	    $retval=$response_split[$i];
	    $retval=~s/^.*\:\s*(.*)$/$1/;
	    last;
	} elsif (($response_split[$i]=~/\sCompression/)&&
		 ($look_for_param eq "compression")&&
		 ($recsettings==$look_for_rs)){
	    # get the compression
	    $retval=$response_split[$i];
	    $retval=~s/^.*\:\s*(.*)$/$1/;
	    last;
	} elsif (($response_split[$i]=~/Current\ssettings/)&&
		 ($look_for_param eq "fringecheck_flag")&&
		 ($look_for_rs==0)&&($recsettings==0)){
	    # determine if the experiment is a fringe test
	    $retval=$response_split[$i];
	    $retval=~s/.*FT\=(.)\s.*/$1/;
	    if ($retval eq "Y"){
		$retval=1;
	    } elsif ($retval eq "N"){
		$retval=0;
	    }
	} elsif (($response_split[$i]=~/Current\srecording\ssettings/)&&
		 ($look_for_param eq "fringecheck_flag")&&
		 ($look_for_rs==1)){
	    $retval=$response_split[$i];
	    $retval=~s/.*FT\=(.)\s.*/$1/;
	} elsif (($response_split[$i]=~/\sVSIB\sMode/)&&
		 ($look_for_param eq "vsib_bits")&&
		 ($recsettings==$look_for_rs)){
	    # get the VSIB mode
	    $retval=$response_split[$i];
	    $retval=~s/^.*\:\s*(.*)$/$1/;
	    if ($retval==3){
		$retval=8;
	    } elsif ($retval==2){
		$retval=16;
	    }
	    last;
	} elsif (($response_split[$i]=~/\sRecord\stime/)&&
		 ($look_for_param eq "record_duration")&&
		 ($recsettings==$look_for_rs)){
	    # get the numerical portion of the recording
	    # duration
	    $retval=$response_split[$i];
	    $retval=~s/^.*\:\s*(.*)$/$1/;
	    if ($look_for_rs==0){
		$retval=substr($retval,0,-1);
	    }
	} elsif (($response_split[$i]=~/\sRecord\stime/)&&
		 ($look_for_param eq "duration_unit")&&
		 ($recsettings==$look_for_rs)){
	    # get the units for the recording duration
	    # ie. h, m or s
	    $retval=$response_split[$i];
	    $retval=~s/^.*\:\s*(.*)$/$1/;
	    $retval=substr($retval,-1);
	} elsif (($response_split[$i]=~/\sOutput\sdisk/)&&
		 ($look_for_param eq "active_disk")&&
		 (($recsettings==0)&&($look_for_rs==0))){
	    # get the currently selected output disk
	    my $tmps;
	    $tmps=$response_split[$i];
	    $tmps=~s/^.*?\:\s*(.*)$/$1/;
	    if ($holdvalue eq "local"){
		$retval=$holdvalue.":".$tmps;
	    } else {
		if ($tmps=~/.*\:$/){
		    $tmps.="eVLBI";
		    $retval=$tmps;
		} else {
		    $retval=$holdvalue.":".$tmps;
		}
	    }
	} elsif (($response_split[$i]=~/Remaining\srecording\stime\son/)&&
		 ($look_for_param eq "active_disk")&&
		 ($look_for_rs==1)){
	    # get the disk that is being recorded to
	    my $tmps=$response_split[$i];
	    $tmps=~/^.*?on\s(.*?)\:(.*?)\:\s(.*)/;
	    $retval=$1.":".$2;
	    $rec_timeleft=$3;
	} elsif (($response_split[$i]=~/\sAuto\sexecute/)&&
		 ($look_for_param eq "auto_experiment")&&
		 ($recsettings==$look_for_rs)){
	    # check whether the server is set to automatically
	    # start experiments
	    $retval=$response_split[$i];
	    $retval=~s/^.*\:\s*(.*)$/$1/;
	    if ($retval eq "enabled"){
		# auto experiment execution is enabled
		$retval=1;
	    } elsif ($retval eq "disabled"){
		# auto experiment execution is disabled
		$retval=0;
	    } elsif ($retval eq "stopped"){
		# auto experiment execution is enabled,
		# but the server has stopped in the middle
		# of an experiment for some reason and has
		# allowed the user to use manual start
		$retval=2;
	    }
	    last;
	} elsif (($response_split[$i]=~/\sAuto\sround\sstart/)&&
		 ($look_for_param eq "auto_rounding")&&
		 ($recsettings==$look_for_rs)){
	    # check whether the recorder will start on
	    # integer block boundaries
	    $retval=$response_split[$i];
	    $retval=~s/^.*\:\s*(.*)$/$1/;
	    if ($retval eq "enabled"){
		# recording will start on integer blocks
		$retval=1;
	    } elsif ($retval eq "disabled"){
		# recording will start immediately
		$retval=0;
	    }
	    last;
#	} elsif (($response_split[$i]=~/\sClean\stime/)&&
#		 ($look_for_param eq "clean_time")){
#	    # check whether the auto cleaning time
#	    # has been set, and if it has, what it
#	    # is set to
#	    $retval=$response_split[$i];
#	    $retval=~s/^.*\:\s*(.*)$/$1/;
#	    if ($retval eq "not enabled"){
#		# no auto cleaning
#		$retval="";
#	    } # otherwise, auto cleaning enabled, or at least
#	      # a time has been set for it
#	    last;
	} elsif (($response_split[$i]=~/\sVSIB\sdevice/)&&
		 ($look_for_param eq "vsib_device")&&
		 ($recsettings==$look_for_rs)){
	    # the location of the VSIB device file
	    $retval=$response_split[$i];
	    $retval=~s/^.*\:\s*(.*)$/$1/;
	    last;
	} elsif (($response_split[$i]=~/\sFile\ssize/)&&
		 ($look_for_param eq "file_size")&&
		 ($recsettings==$look_for_rs)){
	    # the size of the files output by the recorder
	    $retval=$response_split[$i];
	    $retval=~s/^.*\:\s*(.*)$/$1/;
	    $retval=~s/\ssecs/s/;
	    last;
	} elsif (($response_split[$i]=~/\sBlock\ssize/)&&
		 ($look_for_param eq "block_size")&&
		 ($recsettings==$look_for_rs)){
	    # the size of each recorder output block
	    $retval=$response_split[$i];
	    $retval=~s/^.*\:\s*(.*)\sB$/$1/;
	    last;
	} elsif (($response_split[$i]=~/\sClock\srate/)&&
		 ($look_for_param eq "clock_rate")&&
		 ($recsettings==$look_for_rs)){
	    # the rate of the VSIB recorder clock
	    $retval=$response_split[$i];
	    $retval=~s/^.*\:\s*(.*)\sMHz$/$1/;
	    last;
	} elsif (($response_split[$i]=~/\sMark5B\srecording/)&&
		 ($look_for_param eq "mark5b")&&
		 ($recsettings==$look_for_rs)){
	    $retval=$response_split[$i];
	    $retval=~s/^.*\:\s*(.*)$/$1/;
	    if ($retval eq "enabled"){
		$retval=1;
	    } elsif ($retval eq "disabled"){
		$retval=0;
	    }
	    last;
	} elsif (($response_split[$i]=~/\sMark5B\sUDP\sMTU/)&&
		 ($look_for_param eq "udp_datagram_size")&&
		 ($recsettings==$look_for_rs)){
	    $retval=$response_split[$i];
	    $retval=~s/^.*\:\s*(.*)$/$1/;
	    last;
	}
    }
    $retval;
}

sub received_message{
    my $message=<$read_file>;
    for (my $i=0;$i<=$#rec_servers;$i++){
	my @name_els=split(":",$rec_servers[$i]);
	$message=~s/$recorder_ip[$i]/$name_els[0]/;
    }
    my @mels=split(/\n+/,$message);
    for (my $i=0;$i<=$#mels;$i++){
	if ($mels[$i] eq "+++SERVER WARNING+++"){
	    $is_warning=1;
	    last;
	} elsif ($mels[$i] eq "---SERVER INFORMATION---"){
	    $is_warning=0;
	    last;
	} elsif ($mels[$i] eq "++++++++++++++++++++"){
	    $last_warning=1;
	    last;
	} elsif ($last_warning==1){
	    $is_warning=0;
	    $last_warning=0;
	}
    }
    if ($message=~/Server\sacknowledgement\scompleted/){
	if ($registering==1){
	    $is_registered=1;
	} elsif ($registering==-1){
	    $is_remote_registered=1;
	}
	$registering=0;
    }
    if ($is_warning==1){
	logit_red($message);
    } else {
	logit($message);
    }
    return;
}

sub server_comms {
    my @comms_args=@_;
    my ($type,$message,@servers,@actives);
    my $error_switch=1;
    my $not_viewed=0;
    if ($#comms_args==1){
	($type,$message) = @comms_args;
	@servers=@rec_servers;
	@actives=@recorder_active;
    } elsif ($#comms_args==2){
	($type,$message,@servers) = @comms_args;
	for (my $i=0;$i<=$#servers;$i++){
	    $actives[$i]=1;
	}
	$error_switch=0;
	$not_viewed=1;
    }
    
    # create the socket
    my $answer="";
    my $failflag=0;
    my $temp_answer="";
    for (my $i=0;$i<=$#servers;$i++){
	if ($actives[$i]==1){
#	    print "communicating with $servers[$i]\n";
	    $failflag=0;
	    $temp_answer="";
	    my @machine = split(":",$servers[$i]);
	    my @to_view = split(":",$current_recorder);
	    my $socket = IO::Socket::INET->new(PeerAddr => $machine[0],
					       PeerPort => $machine[1],
					       Proto    => "tcp",
					       Type     => SOCK_STREAM);
#	or die "Couldn't connect to $machine[0]:$machine[1] : $!\n";
	    if (!(defined($socket))){
		return("Can't connect to socket");
	    }
#	    print "<$type>$message</$type>\n";
	    print $socket "<$type>$message</$type>";
	    my $temp;
	    while($temp=<$socket>){
		if ((($to_view[0] eq $machine[0])&&
		     ($to_view[1] eq $machine[1]))||
		    ($not_viewed==1)){
		    $answer="$answer$temp";
		} elsif ($temp=~/\<fail\>/){
		    $failflag=1;
		}
		if ($failflag==1){
		    $temp_answer="$temp_answer$temp";
		}
	    }
	    if ($failflag==1){
		# we're not looking at the machine with the error
		# print the error and switch to view the machine
		$temp_answer=&strip_fail($temp_answer);
		logit_red("error from $servers[$i]: $temp_answer\n");
		if ($error_switch==1){
		    $current_recorder=$rec_servers[$i];
		}
	    }
	    close($socket);
	}
    }
    # remove status tags from the answer
    $answer=~s/\<status\>//g;
    $answer=~s/\<\/status\>/\n/g;

    return $answer;
}

sub check_settings {
  my ($settings) = @_;
  my $key;
  my $errmsg = "";
  my $ok = 1;
  # go through each parameter and check that it makes sense

  # antenna
  my $found_antenna = 0;
  foreach $key (keys %Antennas) {
    if ($debug) {print "key = $key\n";}
    if ($key eq $settings->{'antenna'}) {
      $found_antenna = 1;
    } 
  }
  if (!$found_antenna) {
    $errmsg = $errmsg."Antenna given in config file is not known. Should be one of\nthe following:\n";
    foreach $key (keys %Antennas) {
      $errmsg = $errmsg."\t$key\n";
    }
    $errmsg = $errmsg."Note the antenna names are case sensitive.\n\n";
    $ok = 0;
  }

  # log file directory

  # data disk directories

  # max_capacity

  # recorder file size

  # recorder block size

  # vsib device

  if (!$ok) {
    print "$errmsg";
  }
  return ($ok);
}

sub open_log {
  my ($dir,$file) = @_;
  my $ok = 1;
  my $logfile = "$dir/$file";
  if (!open (LOG, "> $logfile")) {
    $ok = 0; 
    print "\nCould not open log file $logfile: $!\n";
  }
  return($ok);
}

sub init_gui {
    $ut_str = "00:00:00";
    $lst_str = "01:01:01";
    if ($debug) {print "Starting GUI...\n";}
    $main = MainWindow->new;
    $main->title("$progname v$progvers");
    $main->iconname("$progname");
    $main->minsize(5, 5);
    $main->positionfrom('user');
    $main->protocol('WM_DELETE_WINDOW' => \&exit_program);
    
    ######################################################################
    ## Frames that contain various logical subsections
    
    my $menu_frame = $main->Frame(-relief => 'raised', 
				  -borderwidth => 2,
				  -background => $value_bg)
	->grid(-row => 0, -column => 0, -columnspan =>4, -sticky => 'we');
    my $time_ant_frame = $main->Frame(-relief => 'flat', 
				      -borderwidth => 0,
				      -background => $value_bg)
	->grid(-row => 10, -column => 0, -columnspan =>4, -sticky => 'ew');
    $disks_frame = $main->Frame(-relief => 'groove', 
				-borderwidth => 2,
				-background => $value_bg)
	->grid(-row => 30, -column => 0, -columnspan =>4, -sticky => 'ew');
    my $recmode_frame = $main->Frame(-relief => 'groove', 
				     -borderwidth => 2,
				     -background => $value_bg)
	->grid(-row => 40, -column => 0, -columnspan =>4, -sticky => 'ew');
    my $experiment_contain_frame = $main->Frame(-relief => 'groove',
						-borderwidth => 2,
						-background => $value_bg)
	->grid(-row => 50, -column => 0,-columnspan => 4,-sticky => 'ew');
    my $experiment_frame = $experiment_contain_frame->Frame(-relief => 'flat',
							    -borderwidth => 2,
							    -background => $value_bg)
	->grid(-row => 0, -column => 0, -columnspan => 1, -sticky => 'ew');
    my $experiment_status_frame = $experiment_contain_frame->Frame(-relief => 'flat',
								   -borderwidth => 2,
								   -background => $value_bg)
	->grid(-row => 0, -column => 2, -columnspan => 2, -sticky => 'ew');
    my $recording_frame = $main->Frame(-relief => 'groove', 
				       -borderwidth => 2,
				       -background => $value_bg)
	->grid(-row => 60, -column => 0, -columnspan => 4, -sticky => 'ew');
#raised, sunken, flat, ridge, solid, and groove.
    my $button_frame = $main->Frame(-relief => 'ridge', 
				    -borderwidth => 3,
				    -background => $value_bg)
	->grid(-row => 65, -column => 0, -columnspan =>4, -sticky => 'ew');
#    my $recorder_server_frame = $main->Frame(-relief => 'flat',
#					     -borderwidth => 0,
#					     -background => $value_bg)
#	->grid(-row => 70, -column => 0, -columnspan => 4, -sticky => 'ew');
    my $log_frame = $main->Frame(-relief => 'groove', 
				 -borderwidth => 0,
				 -background => $value_bg)
	->grid(-row => 90, -column => 0, -columnspan =>4, -sticky => 'ew');
    my $add_log_comment_frame = $main->Frame(-relief => 'groove', 
					     -borderwidth => 0,
					     -background => $value_bg)
	->grid(-row => 100, -column => 0, -columnspan =>4, -sticky => 'ew');
    my $status_and_messages_frame = $main->Frame(-relief => 'groove', 
						 -borderwidth => 0,
						 -background => $value_bg)
	->grid(-row => 110, -column => 0, -columnspan =>4, -sticky => 'ew');
    
    ######################################################################
    ## Items in the Menu frame
    my $menu_b = $menu_frame->Menubutton(-relief => 'flat',
					 -text => 'File', 
					 -underline => 0,
					 -background => $value_bg);
    my $menu = $menu_b->Menu(-tearoff => 0);
    $menu->command(-label => "Exit", 
		   -underline => 0, 
		   -command => \&exit_program,
		   -background => $value_bg);
    $menu_b->pack(-side => 'left');
    $menu_b->configure(-menu => $menu);
    my $cfg_menu_b = $menu_frame->Menubutton(-relief => 'flat',
					     -text => 'Configure', 
					     -underline => 0,
					     -background => $value_bg);
    my $cfg_menu = $cfg_menu_b->Menu(-tearoff => 0);
    $cfg_menu->checkbutton(-label => "Debug messages",
			   -variable => \$debug,
			   -background => $value_bg);
    $cfg_menu_b->pack(-side => 'left');
    $cfg_menu_b->configure(-menu => $cfg_menu);
    my $casc_time=$cfg_menu->cascade(-label => "Update Time",
				     -background => $value_bg);
    my $cfg_time_menu=$cfg_menu->Menu(-tearoff => 0);
    $cfg_time_menu->radiobutton(-label => "5s",
				-font => $font,
				-variable => \$update_time,
				-value => 5,
				-background => $value_bg,
				-command => sub {$main->repeat($update_time*1000,\&server_update)});
    $cfg_time_menu->radiobutton(-label => "10s",
				-font => $font,
				-variable => \$update_time,
				-value => 10,
				-background => $value_bg,
				-command => sub {$main->repeat($update_time*1000,\&server_update)});
    $cfg_time_menu->radiobutton(-label => "20s",
				-font => $font,
				-variable => \$update_time,
				-value => 20,
				-background => $value_bg,
				-command => sub {$main->repeat($update_time*1000,\&server_update)});
    $cfg_time_menu->radiobutton(-label => "30s",
				-font => $font,
				-variable => \$update_time,
				-value => 30,
				-background => $value_bg,
				-command => sub {$main->repeat($update_time*1000,\&server_update)});
    $cfg_time_menu->radiobutton(-label => "1m",
				-font => $font,
				-variable => \$update_time,
				-value => 60,
				-background => $value_bg,
				-command => sub {$main->repeat($update_time*1000,\&server_update)});
    $casc_time->configure(-menu => $cfg_time_menu);
    my $recorderwin_button=$cfg_menu->command(-label => "Show recording settings",
					      -underline => 0,
					      -command => \&recorder_window_ctl,
					      -background => $value_bg);
    my $advanced_button=$cfg_menu->command(-label => "Show advanced settings",
					   -underline => 0,
					   -command => \&advanced_window_ctl,
					   -background => $value_bg);
    my $evlbi_show_button=$cfg_menu->command(-label => "Show eVLBI settings",
					     -underline => 0,
					     -command => \&evlbi_window_ctl,
					     -background => $value_bg);
#    $cleaning_status_label = $menu_frame->Label(-relief => 'raised',
#						-font => $boldfont,
#						-textvariable => \$cleaner_status,
#						-background => $value_bg);
#    $cleaning_status_label->pack(-side => 'right',-ipadx => 10,-padx=>10);
    $recording_status_label = $menu_frame->Label(-relief => 'raised',
						 -font => $boldfont,
						 -textvariable => \$recorder_status,
						 -background => $value_bg);
    $recording_status_label->pack(-side => 'right',-ipadx => 10,-padx=>10);
    my $set_button = $menu_frame->Button(-text => 'SERVER SET',
					 -font => $boldfont,
					 -command => \&update_server,
					 -background => 'yellow');
    $set_button->pack(-side => 'right',-ipadx => 10,-padx=>10);
    
    ######################################################################
    ## Items in the Time frame
    $time_ant_frame->Label(-relief => 'flat',
			   -font => $boldfont,
			   -text => "Antenna :",
			   -background => $value_bg)
	->grid(-column => 0, -row => 0, -sticky => 'e');
    $time_ant_frame->Label(-relief => 'flat',
			   -font => $font,
			   -text => "$settings->{'antenna'}",
			   -background => $value_bg)
	->grid(-column => 1, -row => 0, -sticky => 'w');
    $time_ant_frame->Label(-relief => 'flat',
			   -font => $boldfont,
			   -text => "Server :",
			   -background => $value_bg)
	->grid(-column => 2, -row => 0, -padx => 5, -pady => 0);
    $time_ant_frame->Label(-relief => 'flat',
			   -font => $font,
			   -textvariable => \$current_recorder,
			   -background => $value_bg)
	->grid(-column => 3, -row => 0, -padx => 5, -pady => 0);
    my $UT_box = $time_ant_frame->Label(-relief => 'flat',
					-font => $boldfont,
					-textvariable => \$ut_str,
					-width => 24,
					-background => $value_bg)
	->grid(-column => 4, -row => 0, -padx => 5, -pady => 0);
    my $LST_box = $time_ant_frame->Label(-relief => 'flat',
					 -font => $boldfont,
					 -textvariable => \$lst_str,
					 -width => 12,
					 -background => $value_bg)
	->grid(-column => 5, -row => 0, -padx => 5, -pady => 0);
    $time_ant_frame->Label(-relief => 'flat',
			   -font => $boldfont,
			   -text => "Uptime :",
			   -background => $value_bg)
	->grid(-column => 6, -row => 0, -padx => 5, -pady => 0);
    $uptime_label=$time_ant_frame->Label(-relief => 'flat',
					 -font => $font,
					 -textvariable => \$server_uptime,
					 -background => $value_bg)
	->grid(-column => 7, -row => 0, -padx => 5, -pady => 0);
    
    # Update the time strings every 500 ms
    $time_ant_frame->repeat(500, \&get_times);
    

    ######################################################################
    ## Items in the Recorder mode frame $recmode_frame
    $recmode_frame->Label(-relief => 'flat',
			  -font => $boldfont,
			  -text => "     Experiment :",
			  -background => $value_bg)
	->grid(-column => 0, -row => 0, -sticky => 'e');
    $recmode_frame->Entry(-width => 8, 
			  -textvariable => \$Current_Parameters{"experiment_name"},
			  -font => $font, 
			  -background => $entry_bg)
	->grid(-column => 1, -row => 0, -sticky => 'w');
    $recmode_frame->Checkbutton(-text => "Fringe Check?",
				-background => $value_bg,
				-font => $boldfont,
				-command => \&update_server,
				-variable => \$Current_Parameters{"fringecheck_flag"})
	->grid(-column => 2,-row => 0,-sticky => 'w');
    $recmode_frame->Label(-relief => 'flat',
			  -font => $boldfont,
			  -text => "Bandwidth per channel (MHz)",
			  -background => $value_bg)
	->grid(-column => 0, -row => 1, -sticky => 'e');
    $recmode_frame->BrowseEntry(
				-choices => \@bandwidths,
				-variable => \$Current_Parameters{"bandwidth"},
				-autolimitheight => 'true',
				-listheight => ($#bandwidths+1),
				-autolistwidth => 'true',
				-listwidth => 10,
				-width => 3,
				-background => $value_bg,
				-browsecmd => \&update_server,
				-state => 'normal'
				)
	->grid(-column => 1, -row => 1, -sticky => 'w');
    $recmode_frame->Label(-relief => 'flat',
			  -text => "Duration",
			  -font => $boldfont,
			  -background => $value_bg)
	->grid(-column => 2, -row => 1, -sticky => 'e');
    $recmode_frame->Entry(-width => 4,
			  -textvariable => \$Current_Parameters{"record_duration"},
			  -font => $font,
			  -background => $entry_bg)
	->grid(-column => 3, -row => 1, -sticky => 'w');
    $record_dur_unit=$record_units[0];
    for (my $r=1;$r<=$#record_units+1;$r++){
	$recmode_frame->Radiobutton(-text => "$record_units[$r-1]",
				    -font => $font,
				    -variable => \$Current_Parameters{"duration_unit"},
				    -value => $record_units[$r-1],
				    -background => $value_bg)
	    ->grid(-column => (3+$r),-row => 1,-sticky => 'w');
    }
    $recmode_frame->Label(-relief => 'flat',
			  -font => $boldfont,
			  -text => "Channel Selection",
			  -background => $value_bg)
	->grid(-column => 0, -row => 2, -sticky => 'e');
    $chan_sel_entry=$recmode_frame->BrowseEntry(
						-choices => \@single_bw16_rec_modes,
						-variable => \$rec_mode,
						-autolimitheight => 'true',
						-listheight => ($#single_bw16_rec_modes+1),
						-autolistwidth => 'true',
						-listwidth => 30,
						-width => 12,
						-background => $value_bg,
						-state => 'normal',
						-browsecmd => \&record_mode_set)
	->grid(-column => 1, -row => 2, -sticky => 'w');
    $nbits_label = $recmode_frame->Label(-relief => 'flat',
					 -font => $boldfont,
					 -text => "Number of bits",
					 -background => $value_bg)
	->grid(-column => 2, -row => 2, -sticky => 'e');
    $nbits_entry = $recmode_frame->BrowseEntry(
					       -choices => \@available_number_of_bits,
					       -variable => \$Current_Parameters{"vsib_bits"},
					       -autolimitheight => 'true',
					       -listheight => ($#available_number_of_bits+1),
					       -autolistwidth => 'true',
					       -listwidth => 30,
					       -width => 4,
					       -background => $value_bg,
					       -state => 'disabled',
					       -browsecmd => \&update_server
					       )
	->grid(-column => 3, -row => 2, -sticky => 'w');
    $compress_label = $recmode_frame->Label(-relief => 'flat',
					    -font => $boldfont,
					    -text => "Compression mode",
					    -background => $value_bg)
	->grid(-column => 2, -row => 3, -sticky => 'e');
    $compress_entry = $recmode_frame->BrowseEntry(
						  -choices => \@available_compress_modes,
						  -variable => \$Current_Parameters{"compression"},
						  -autolimitheight => 'true',
						  -listheight => ($#available_compress_modes+1),
						  -autolistwidth => 'true',
						  -listwidth => 30,
						  -width => 4,
						  -background => $value_bg,
						  -state => 'disabled',
						  -browsecmd => \&update_server
						  )
	->grid(-column => 3, -row => 3, -sticky => 'w');
    $recmode_frame->Label(-relief => 'flat',
			  -font => $boldfont,
			  -text => "Bit rate (Mbps)",
			  -background => $value_bg)
	->grid(-column => 0, -row => 3, -sticky => 'e');
    $recmode_frame->Label(-relief => 'flat',
			  -font => $font,
			  -textvariable => \$rate,
			  -background => $value_bg)
	->grid(-column => 1, -row => 3, -sticky => 'w');
    
    ######################################################################
    ## Items in the Experiment control frame $experiment_frame
    # A list of the experiments
    $experiment_frame->Label(-relief => 'flat',
			     -text => 'Experiments:', -font => $boldfont,
			     -background => $value_bg)
	->grid(-column => 0, -row => 0, -sticky => 'w');
    $experiment_frame->Label(-relief => 'flat',
			     -text => "Available", 
			     -font => $boldfont,
			     -background => $value_bg)
	->grid(-column => 1, -row => 0, -sticky => 'ew');
    $available_experiments = $experiment_frame->BrowseEntry(-choices => \@experiment_available,
							    -variable => \$ea_select,
							    -autolimitheight => 'true',
							    -listheight => ($#experiment_available+1),
							    -listwidth => 30,
							    -width => 12,
							    -background => $value_bg,
							    -state => 'readonly'
							    )
	->grid(-column => 2, -row => 0, -sticky => 'ew');
    
    $experiment_frame->Label(-relief => 'flat',
			     -text => "Loaded", 
			     -font => $boldfont,
			     -background => $value_bg)
	->grid(-column => 3, -row => 0, -sticky => 'ew');
    $loaded_experiments = $experiment_frame->BrowseEntry(-choices => \@experiment_loaded,
							 -variable => \$el_select,
							 -autolimitheight => 'true',
							 -listheight => ($#experiment_loaded+1),
							 -listwidth => 30,
							 -width => 12,
							 -background => $value_bg,
							 -state => 'readonly')
	->grid(-column => 4, -row => 0, -sticky => 'ew');
    
    $load_experiment_button=$experiment_frame->Button(-text => 'Load',
						      -font => $boldfont,
						      -width => 8,
						      -height => 1,
						      -command => \&load_experiment,
						      -background => 'yellow')
	->grid(-column =>2, -row => 1, -sticky => 'ew', -columnspan => 1);
    $unload_experiment_button=$experiment_frame->Button(-text => 'Unload',
							-font => $boldfont,
							-width => 8,
							-command => \&unload_experiment,
							-background => 'yellow')
	->grid(-column =>4, -row => 1, -sticky => 'ew', -columnspan => 1);
    
    ######################################################################
    ## Items in the Experiment status frame $experiment_status_frame
    $experiment_status_frame->Label(-relief => 'flat',
				    -text => "Current Experiment:", -font => $boldfont,
				    -background => $value_bg)
	->grid(-column => 0, -row => 0, -sticky => 'e');
    $experiment_status_frame->Label(-relief => 'flat',
				    -font => $font,
				    -textvariable => \$current_experiment,
				    -background => $value_bg)
	->grid(-column => 1, -row => 0, -sticky => 'w');
    $experiment_status_frame->Label(-relief => 'flat',
				    -text => "Time until finished:", -font => $boldfont,
				    -background => $value_bg)
	->grid(-column => 0, -row => 1, -sticky => 'e');
    $experiment_status_frame->Label(-relief => 'flat',
				    -font => $font,
				    -textvariable => \$ce_timetoend,
				    -background => $value_bg)
	->grid(-column => 1, -row => 1, -sticky => 'w');
    $experiment_status_frame->Label(-relief => 'flat',
				    -text => "Next Experiment:", -font => $boldfont,
				    -background => $value_bg)
	->grid(-column => 0, -row => 2, -sticky => 'e');
    $experiment_status_frame->Label(-relief => 'flat',
				    -font => $font,
				    -textvariable => \$next_experiment,
				    -background => $value_bg)
	->grid(-column => 1, -row => 2, -sticky => 'w');
    $experiment_status_frame->Label(-relief => 'flat',
				    -text => "Time until start:", -font => $boldfont,
				    -background => $value_bg)
	->grid(-column => 0, -row => 3, -sticky => 'e');
    $experiment_status_frame->Label(-relief => 'flat',
				    -font => $font,
				    -textvariable => \$ne_timetostart,
				    -background => $value_bg)
	->grid(-column => 1, -row => 3, -sticky => 'w');
    
    
    
    ######################################################################
    ## Items in the Recording control frame $recording_frame
    # Observation type: scheduled or manual start
    my $recframe_one=$recording_frame->Frame(-relief => 'flat',
					     -borderwidth => 0,
					     -background => $value_bg)
	->grid(-row => 0, -column => 0, -columnspan => 4, -sticky => 'ew');
    my $recframe_two=$recording_frame->Frame(-relief => 'flat',
					     -borderwidth => 0,
					     -background => $value_bg)
	->grid(-row => 2, -column => 0, -columnspan => 4, -sticky => 'ew');
    my $recframe_three=$recording_frame->Frame(-relief => 'flat',
					       -borderwidth => 0,
					       -background => $value_bg)
	->grid(-row => 1, -column => 0, -columnspan => 4, -sticky => 'ew');
    $recframe_one->Checkbutton(-text => "Auto Experiment Execution",
			       -font => $boldfont,
			       -variable => \$Current_Parameters{"auto_experiment"},
			       -command => \&update_server,
			       -background => $value_bg)
	->grid(-column => 0, -row => 0, -sticky => 'w');
    $huygens_button=$recframe_one->Checkbutton(-text => "Rounded start",
					       -font => $boldfont,
					       -variable => \$Current_Parameters{"auto_rounding"},
					       -command => \&update_server,
					       -background => $value_bg)
	->grid(-column => 1, -row => 0, -sticky => 'w');
    $recframe_one->Checkbutton(-text => "Huygen's Cable",
			       -font => $boldfont,
			       -variable => \$huygens_cable,
			       -background => $value_bg,
			       -command => \&set_mode_options)
	->grid(-column => 2, -row => 0, -sticky => 'w');
    $recframe_one->Checkbutton(-text => "Mark5B recording",
			       -font => $boldfont,
			       -variable => \$Current_Parameters{"mark5b"},
			       -background => $value_bg,
			       -command => \&update_server)
	->grid(-column => 3, -row => 0, -sticky => 'w');
#    $recframe_three->Label(-relief => 'flat',
#			   -text => "Disk cleaning:",
#			   -font => $boldfont,
#			   -background => $value_bg)
#	->grid(-column => 0, -row => 0, -sticky => 'w');
#    $recframe_three->Label(-relief => 'flat',
#			   -text => "Time:",
#			   -font => $font,
#			   -background => $value_bg)
#	->grid(-column => 1, -row => 0, -sticky => 'w');
#    $recframe_three->Entry(-width => 4,
#			   -textvariable => \$Current_Parameters{"clean_time"},
#			   -font => $font,
#			   -background => $entry_bg)
#	->grid(-column => 2, -row => 0, -sticky => 'w');
#    $recframe_three->Button(-text => 'Start',
#			    -font => $font,
#			    -width => 4,
#			    -command => \&start_cleaner,
#			    -background => $value_bg)
#	->grid(-column => 3, -row => 0, -sticky => 'ew');
#    $recframe_three->Button(-text => 'Stop',
#			    -font => $font,
#			    -width => 4,
#			    -command => \&stop_cleaner,
#			    -background => $value_bg)
#	->grid(-column => 4, -row => 0, -sticky => 'ew');
    $recframe_two->Checkbutton(-text => "Scheduled start",
			       -font => $boldfont,
			       -offvalue => 0,
			       -onvalue => 1,
			       -variable => \$scheduled_start,
			       -command => \&set_mode_options,
			       -background => $value_bg)
	->grid(-column => 0, -row => 0, -sticky => 'w');
    $recframe_two->Label(-relief => 'flat',
			 -text => "Year:",
			 -font => $font,
			 -background => $value_bg)
	->grid(-column => 1, -row => 0, -sticky => 'w');
    $y_e = $recframe_two->Entry(-width => 4, 
				-textvariable => \$start_y, 
				-font => $font, 
				-background => $entry_bg)
	->grid(-column => 2, -row => 0, -sticky => 'w');
    $recframe_two->Label(-relief => 'flat',
			 -text => "Day:", 
			 -font => $font,
			 -background => $value_bg)
	->grid(-column => 3, -row => 0, -sticky => 'w');
    $d_e = $recframe_two->Entry(-width => 3, 
				-textvariable => \$start_d, 
				-font => $font, 
				-background => $entry_bg)
	->grid(-column => 4, -row => 0, -sticky => 'w');
    $recframe_two->Label(-relief => 'flat',
			 -text => "h:", 
			 -font => $font,
			 -background => $value_bg)
	->grid(-column => 5, -row => 0, -sticky => 'w');
    $h_e = $recframe_two->Entry(-width => 2, 
				-textvariable => \$start_h, 
				-font => $font, 
				-background => $entry_bg)
	->grid(-column => 6, -row => 0, -sticky => 'w');
    $recframe_two->Label(-relief => 'flat',
			 -text => "m:", 
			 -font => $font,
			 -background => $value_bg)
	->grid(-column => 7, -row => 0, -sticky => 'w');
    $m_e = $recframe_two->Entry(-width => 2, 
				-textvariable => \$start_m, 
				-font => $font, 
				-background => $entry_bg)
	->grid(-column => 8, -row => 0, -sticky => 'w');
    $recframe_two->Label(-relief => 'flat',
			 -text => "s:", 
			 -font => $font,
			 -background => $value_bg)
	->grid(-column => 9, -row => 0, -sticky => 'w');
    $s_e = $recframe_two->Entry(-width => 2, 
				-textvariable => \$start_s, 
				-font => $font, 
				-background => $entry_bg)
	->grid(-column => 10, -row => 0, -sticky => 'w');
    
    $recframe_two->Button(-text => 'Now+10s',
			  -font => $font,
			  -width => 4,
			  -command => \&get_start_ydhms,
			  -background => $value_bg)
	->grid(-column => 11, -row => 0, -sticky => 'w');
    
    ######################################################################
    ## Items in the start/stop frame $button_frame
    $start_button = $button_frame->Button(-text => 'Start',
					  -font => $boldfont,
					  -width => 10,
					  -command => \&start_recording,
					  -background => 'light green')
	->grid(-column => 0, -row => 0, -columnspan => 1, -sticky => 'ew');
    $stop_button = $button_frame->Button(-text => 'Stop',
					 -font => $boldfont,
					 -width => 10,
					 -command => \&stop_recording,
					 -background => 'pink')
	->grid(-column => 1, -row => 0, -columnspan => 1,-sticky => 'ew');
    # disable both buttons until we know the server state
    $start_button->configure(-state => 'disable');
    $stop_button->configure(-state => 'disable');
    
    ######################################################################
    ## Items in the Log frame $log_frame
    $log_frame->Label(-relief => 'flat',
		      -text => "Log :", -font => $boldfont,
		      -background => $value_bg)
	->pack(-anchor => 'w');
    $log_t = $log_frame->Scrolled('Text',
				  -relief => 'sunken',
				  -borderwidth => 2,
				  -setgrid => 'true',
				  -width => 80,
				  -height => 10,
				  -background => $value_bg,
				  -scrollbars => 'e')
	->pack(-expand => 1, -fill =>  'both');
    $log_t->mark(qw/set insert 0.0/);
    $log_t->tagConfigure('r', 'foreground', 'red');
    $log_t->tagConfigure('g', 'foreground', 'darkgreen');
    $log_t->tagConfigure('b', 'foreground', 'blue');
    $log_t->tagConfigure('y', 'foreground', 'blue', 'background', 'yellow');
    my $time =get_log_timestr();
    $log_t->insert('0.0',"$time $progname version $progvers.\n",'y');
    print LOG "$time $progname version $progvers.\n";
    $log_t->insert('end',"$time Log file $logfile opened.\n");
    print LOG "$time Log file $logfile opened.\n";
    
    ######################################################################
    ## Items in the Add Log Comment frame
    
    # Comment entry:
    $add_log_comment_frame->Label(-relief => 'flat',
				  -text => "Comment :", -font => $boldfont,
				  -background => $value_bg)
	->grid(-row =>0, -column => 0, -columnspan => 1, -sticky => 'e');
    my $comment_entry = $add_log_comment_frame->Entry(-width => 70, 
						      -textvariable => \$comment, 
						      -font => $font, 
						      -background => $entry_bg)
	->grid(-row =>0, -column => 1, -columnspan => 39, -sticky => 'ew');
    $ok_button = $add_log_comment_frame->Button(-text    => "OK", -font => $boldfont,
						-width => 4, -justify => 'left',
						-command => \&enter_comment,
						-background => $value_bg)
	->grid(-row => 0, -column => 41, -sticky => 'e');
    $comment_entry->bind("<Return>",\&enter_comment);
    
    $add_log_comment_frame->Label(-relief => 'flat',
				  -font => $boldfont,
				  -text => "Template comments",
				  -background => $value_bg)
	->grid(-column => 0, -row => 2, -sticky => 'e');
    $add_log_comment_frame->BrowseEntry(
					-choices => \@template_comments,
					-variable => \$template_comment,
					-autolimitheight => 'true',
					-listheight => ($#template_comments+1),
					-listwidth => 400,
					-width => 70,
					-background => $value_bg,
					-browsecmd => sub {$comment = $template_comment; 
							   $template_comment = $template_comments[0];
						       }
					)
	->grid(-column => 1, -row => 2, -sticky => 'w');
    

    # we now have the recorder status in another window for many reasons
    $recorderwin=MainWindow->new();
    $recorderwin->title("Recording Information - Last Recording");
    $recorderwin->iconname("$progname recording info");
    $recorderwin->minsize(5,5);
    $recorderwin->positionfrom('user');
    $recorderwin->withdraw;
    $recorderwin->protocol('WM_DELETE_WINDOW' => sub {$recorderwin->withdraw; $show_recorderwin=0});
    $recsettings_frame = $recorderwin->Frame(-relief => 'groove',
					     -borderwidth => 2,
					     -background => $value_bg)
	->grid(-row => 0, -column => 0, -columnspan =>4, -sticky => 'ew');
    $recdisk_frame = $recorderwin->Frame(-relief => 'groove',
					 -borderwidth => 2,
					 -background => $value_bg)
	->grid(-row => 1, -column => 0, -columnspan => 4, -sticky => 'ew');
    $stats_frame = $recorderwin->Frame(-relief => 'groove', 
				       -borderwidth => 2,
				       -background => $value_bg)
	->grid(-row => 2, -column => 0, -columnspan =>4, -sticky => 'ew');
    ######################################################################
    ## Items in the Recorder settings frame $recsettings_frame
    $recsettings_frame->Label(-relief => 'flat',
			      -font => $boldfont,
			      -text => "Experiment:",
			      -background => $value_bg)
	->grid(-column => 0, -row => 0, -sticky => 'e');
    $recsettings_frame->Label(-relief => 'flat',
			      -font => $font,
			      -textvariable => \$Current_Parameters{"rs_experiment_name"},
			      -background => $value_bg)
	->grid(-column => 1, -row => 0, -sticky => 'w');
    $recsettings_frame->Label(-relief => 'flat',
			      -font => $boldfont,
			      -text => "Fringe Check:",
			      -background => $value_bg)
	->grid(-column => 2, -row => 0, -sticky => 'e');
    $recsettings_frame->Label(-relief => 'flat',
			      -font => $font,
			      -textvariable => \$Current_Parameters{"rs_fringecheck_flag"},
			      -background => $value_bg)
	->grid(-column => 3, -row => 0, -sticky => 'w');
    $recsettings_frame->Label(-relief => 'flat',
			      -font => $boldfont,
			      -text => "Bandwidth per channel (MHz):",
			      -background => $value_bg)
	->grid(-column => 0, -row => 1, -sticky => 'e');
    $recsettings_frame->Label(-relief => 'flat',
			      -font => $font,
			      -textvariable => \$Current_Parameters{"rs_bandwidth"},
			      -background => $value_bg)
	->grid(-column => 1, -row => 1, -sticky => 'w');
    $recsettings_frame->Label(-relief => 'flat',
			      -font => $boldfont,
			      -text => "Duration:",
			      -background => $value_bg)
	->grid(-column => 2, -row => 1, -sticky => 'e');
    $recsettings_frame->Label(-relief => 'flat',
			      -font => $font,
			      -textvariable => \$Current_Parameters{"rs_record_duration"},
			      -background => $value_bg)
	->grid(-column => 3, -row => 1, -sticky => 'w');
    $recsettings_frame->Label(-relief => 'flat',
			      -font => $boldfont,
			      -text => "Compression Mode:",
			      -background => $value_bg)
	->grid(-column => 0, -row => 2, -sticky => 'e');
    $recsettings_frame->Label(-relief => 'flat',
			      -font => $font,
			      -textvariable => \$Current_Parameters{"rs_compression"},
			      -background => $value_bg)
	->grid(-column => 1, -row => 2, -sticky => 'w');
    $recsettings_frame->Label(-relief => 'flat',
			      -font => $boldfont,
			      -text => "Number of bits:",
			      -background => $value_bg)
	->grid(-column => 2, -row => 2, -sticky => 'e');
    $recsettings_frame->Label(-relief => 'flat',
			      -font => $font,
			      -textvariable => \$Current_Parameters{"rs_vsib_bits"},
			      -background => $value_bg)
	->grid(-column => 3, -row => 2, -sticky => 'w');
    $recsettings_frame->Label(-relief => 'flat',
			      -font => $boldfont,
			      -text => "Bit rate (Mbps):",
			      -background => $value_bg)
	->grid(-column => 0, -row => 3, -sticky => 'e');
    $recsettings_frame->Label(-relief => 'flat',
			      -font => $font,
			      -textvariable => \$recording_rate,
			      -background => $value_bg)
	->grid(-column => 1, -row => 3, -sticky => 'w');

    ######################################################################
    ## Items in the Recorder statistics frame $stats_frame
    my $stats_frame_one=$stats_frame->Frame(-relief => 'flat',
					    -borderwidth => 0,
					    -background => $value_bg)
	->grid(-row => 0, -column => 0, -columnspan => 4, -sticky => 'ew');
    my $stats_frame_two=$stats_frame->Frame(-relief => 'flat',
					    -borderwidth => 0,
					    -background => $value_bg)
	->grid(-row => 0, -column => 4, -columnspan => 4, -sticky => 'ew');
    
    $stats_frame_one->Label(-relief => 'flat',
			    -text => "Last 1PPS :", -font => $boldfont,
			    -background => $value_bg)
	->grid(-column => 0, -row => 0, -sticky => 'w');
    $stats_frame_one->Label(-textvariable => \$tv_last_pps,
			    -width => 8,
			    -font => $font, 
			    -relief => 'flat',
			    -background => $value_bg)
	->grid(-column => 1, -row => 0, -sticky => 'ew');
    
    $stats_frame_one->Label(-relief => 'flat',
			    -text => "Missed 1PPS :", -font => $boldfont,
			    -background => $value_bg)
	->grid(-column => 0, -row => 1, -sticky => 'w');
    $stats_frame_one->Label(-textvariable => \$tv_stats,
			    -width => 18,
			    -font => $font, 
			    -relief => 'flat',
			    -background => $value_bg)
	->grid(-column => 1, -row => 1, -sticky => 'ew');
    
    $stats_frame_one->Label(-relief => 'flat',
			    -text => "Last Bigbuf :", -font => $boldfont,
			    -background => $value_bg)
	->grid(-column => 0, -row => 2, -sticky => 'w');
    $stats_frame_one->Label(-textvariable => \$tv_last_bigbuf,
			    -width => 3,
			    -font => $font, 
			    -relief => 'flat',
			    -background => $value_bg)
	->grid(-column => 1, -row => 2, -sticky => 'ew');
    $stats_frame_one->Label(-relief => 'flat',
			    -text => "Last block :", -font => $boldfont,
			    -background => $value_bg)
	->grid(-column => 0, -row => 3, -sticky => 'w');
    $stats_frame_one->Label(-textvariable => \$tv_last_block,
			    -width => 18,
			    -font => $font, 
			    -relief => 'flat',
			    -background => $value_bg)
	->grid(-column => 1, -row => 3, -sticky => 'ew');
    $stats_frame_one->Label(-relief => 'flat',
			    -text => "Last file :", -font => $boldfont,
			    -background => $value_bg)
	->grid(-column => 0, -row => 4, -sticky => 'w');
    $stats_frame_one->Label(-textvariable => \$tv_last_filename,
			    -width => 26,
			    -font => $font,
			    -relief => 'flat',
			    -background => $value_bg)
	->grid(-column => 1, -row => 4, -sticky => 'ew');
    $stats_frame_two->Label(-relief => 'flat',
			    -text => "Sampler statistics :", -font => $boldfont,
			    -background => $value_bg)
	->grid(-column => 0, -row => 0, -sticky => 'w');
    $stats_frame_two->Message(-textvariable => \$sampler_stats,
			      -width => 500,
			      -font => $font,
			      -relief => 'flat',
			      -background => $value_bg)
	->grid(-column => 0, -row => 1, -sticky => 'e');
			  
    
    
    $errorwin = MainWindow->new();
    $errorwin->title("Error");
    $errorwin->minsize(50, 10);
    $errorwin->geometry('+500+500');
    $errorwin->withdraw;
    $err_msg = $errorwin->Label (
				 -background => 'red',
				 -borderwidth => '5',
				 -foreground => 'yellow',
				 -padx => '4',
				 -text => "all OK",
				 )->pack;
    $err_frame1 = $errorwin->Frame (
				    -background => 'red',
				    -borderwidth => '0',
				    )->pack(-fill => 'x');
    $err_frame1->Button (
			 -activebackground => 'magenta',
			 -activeforeground => 'yellow',
			 -background => 'red',
			 -borderwidth => '5',
			 -foreground => 'yellow',
			 -relief => 'groove',
			 -command => sub {$errorwin->withdraw;$errorwin_free=1},
			 -text => 'OK',
			 )->pack();
    
    
    ######################################################################
    ## Items in the Disks frame $disks_frame
    &disks_display();
    
    $err_frame1->repeat(510, \&start_dialogs);
    # call the update routine every $update_time seconds
    # (repeat wants the value in ms)
    $main->repeat($update_time*1000,\&server_update);
    
    # window with advanced settings
    $advanced = MainWindow->new();
    $advanced->title("$progname advanced settings");
    $advanced->iconname("$progname advanced");
    $advanced->minsize(5,5);
    $advanced->positionfrom('user');
    $advanced->withdraw;
    $advanced->protocol('WM_DELETE_WINDOW' => sub {$advanced->withdraw; $show_advanced=0});
    
    my $advanced_frame = $advanced->Frame(-relief => 'raised',
					  -borderwidth => 2,
					  -background => $value_bg)
	->grid(-row => 0, -column => 0, -columnspan => 2, -sticky => 'we');
    my $advanced_button_frame = $advanced->Frame(-relief => 'flat',
						 -borderwidth => 0,
						 -background => $value_bg)
	->grid(-row => 1, -column => 0, -columnspan => 2, -sticky => 'we');
    $advanced_frame->Label(-relief => 'flat',
			   -font => $boldfont,
			   -text => "VSIB device :",
			   -background => $value_bg)
	->grid(-column => 0, -row => 0, -sticky => 'e');
    $advanced_frame->Entry(-width => 20,
			   -textvariable => \$Current_Parameters{"vsib_device"},
			   -font => $font,
			   -background => $entry_bg)
	->grid(-column => 1, -row => 0, -sticky => 'w');
    $advanced_frame->Label(-relief => 'flat',
			   -font => $boldfont,
			   -text => "File size :",
			   -background => $value_bg)
	->grid(-column => 0, -row => 1, -sticky => 'e');
    $advanced_frame->Entry(-width => 5,
			   -textvariable => \$Current_Parameters{"file_size"},
			   -font => $font,
			   -background => $entry_bg)
	->grid(-column => 1, -row => 1, -sticky => 'w');
    $advanced_frame->Label(-relief => 'flat',
			   -font => $boldfont,
			   -text => "Block size (B) :",
			   -background => $value_bg)
	->grid(-column => 0, -row => 2, -sticky => 'e');
    $advanced_frame->Entry(-width => 8,
			   -textvariable => \$Current_Parameters{"block_size"},
			   -font => $font,
			   -background => $entry_bg)
	->grid(-column => 1, -row => 2, -sticky => 'w');
    $advanced_frame->Label(-relief => 'flat',
			   -font => $boldfont,
			   -text => "Clock rate (MHz) :",
			   -background => $value_bg)
	->grid(-column => 0, -row => 3, -sticky => 'e');
    $advanced_frame->Entry(-width => 5,
			   -textvariable => \$Current_Parameters{"clock_rate"},
			   -font => $font,
			   -background => $entry_bg)
	->grid(-column => 1, -row => 3, -sticky => 'w');
    $advanced_button_frame->Button(-text => 'Set from file',
				   -font => $boldfont,
				   -width => 40,
				   -command => sub { &parameter_fileset("advanced"); },
				   -background => 'yellow')
	->grid(-column => 0, -row => 0, -sticky => 'ew');

    # window with eVLBI settings
    $evlbi = MainWindow->new();
    $evlbi->title("$progname eVLBI settings");
    $evlbi->iconname("$progname eVLBI");
    $evlbi->minsize(5,5);
    $evlbi->positionfrom('user');
    $evlbi->withdraw;
    $evlbi->protocol('WM_DELETE_WINDOW' => sub {$evlbi->withdraw; $show_evlbi=0});

    $remote_frame = $evlbi->Frame(-relief => 'raised',
				  -borderwidth => 2,
				  -background => $value_bg)
	->grid(-row => 0, -column => 0, -columnspan => 2, -sticky => 'we');
    
    &remotehost_display();

    my $evlbi_frame = $evlbi->Frame(-relief => 'raised',
				    -borderwidth => 2,
				    -background => $value_bg)
	->grid(-row => 1, -column => 0, -columnspan => 2, -sticky => 'we');
    my $evlbi_button_frame = $evlbi->Frame(-relief => 'flat',
					   -borderwidth => 0,
					   -background => $value_bg)
	->grid(-row => 2, -column => 0, -columnspan => 2, -sticky => 'we');
    $evlbi_frame->Label(-relief => 'flat',
			-font => $boldfont,
			-text => "Nickname :",
			-background => $value_bg)
	->grid(-column => 0, -row => 0, -sticky => 'e');
    $evlbi_nickname=$evlbi_frame->Entry(-width => 30,
					-textvariable => \$Current_Parameters{"remote_commonname"},
					-font => $font,
					-background => $entry_bg)
	->grid(-column => 1, -row => 0, -sticky => 'w');
    $evlbi_frame->Label(-relief => 'flat',
			-font => $boldfont,
			-text => "Remote Hostname :",
			-background => $value_bg)
	->grid(-column => 0, -row => 1, -sticky => 'e');
    $evlbi_host=$evlbi_frame->Entry(-width => 30,
				    -textvariable => \$Current_Parameters{"remote_host"},
				    -font => $font,
				    -background => $entry_bg)
	->grid(-column => 1, -row => 1, -sticky => 'w');
    $evlbi_frame->Label(-relief => 'flat',
			-font => $boldfont,
			-text => "TCP Port # :",
			-background => $value_bg)
	->grid(-column => 0, -row => 2, -sticky => 'e');
    $evlbi_port=$evlbi_frame->Entry(-width => 6,
				    -textvariable => \$Current_Parameters{"tcp_port"},
				    -font => $font,
				    -background => $entry_bg)
	->grid(-column => 1, -row => 2, -sticky => 'w');
    $evlbi_frame->Label(-relief => 'flat',
			-font => $boldfont,
			-text => "TCP Window Size (kB) :",
			-background => $value_bg)
	->grid(-column => 0, -row => 3, -sticky => 'e');
    $evlbi_window=$evlbi_frame->Entry(-width => 6,
				      -textvariable => \$Current_Parameters{"tcp_window_size"},
				      -font => $font,
				      -background => $entry_bg)
	->grid(-column => 1, -row => 3, -sticky => 'w');
    $evlbi_frame->Label(-relief => 'flat',
			-font => $boldfont,
			-text => "UDP Datagram Size (kB) :",
			-background => $value_bg)
	->grid(-column => 0, -row => 4, -sticky => 'e');
    $evlbi_datagram=$evlbi_frame->Entry(-width => 6,
					-textvariable => \$Current_Parameters{"udp_datagram_size"},
					-font=> $font,
					-background => $entry_bg)
	->grid(-column => 1, -row => 4, -sticky => 'w');
    $evlbi_frame->Label(-relief => 'flat',
			-font => $boldfont,
			-text => "eVLBI target? :",
			-background => $value_bg)
	->grid(-column => 0,-row => 5, -sticky => 'e');
    $evlbi_selector=$evlbi_frame->Checkbutton(-font => $boldfont,
					      -offvalue => 0,
					      -onvalue => 1,
					      -variable => \$Current_Parameters{"evlbi_target"},
					      -background => $value_bg)
	->grid(-column => 1, -row => 5, -sticky => 'w');
    $evlbi_frame->Label(-relief => 'flat',
			-font => $boldfont,
			-text => "Enable immediately? :",
			-background => $value_bg)
	->grid(-column => 0, -row => 6, -sticky => 'e');
    $evlbi_frame->Checkbutton(-font => $boldfont,
			      -offvalue => 0,
			      -onvalue => 1,
			      -variable => \$Current_Parameters{"evlbi_enable_immediately"},
			      -background => $value_bg)
	->grid(-column => 1, -row => 6, -sticky => 'w');
    $evlbi_button=$evlbi_button_frame->Button(-text => 'Add Host',
					      -font => $boldfont,
					      -width => 26,
					      -command => \&add_new_remote_host,
					      -background => 'yellow')
	->grid(-column => 0, -row => 0, -sticky => 'ew');
    
}

sub add_new_remote_host {
    # this sub takes a remote host specification and
    # sends its details to the server we're talking to

    # first check that we have enough info
    if (($Current_Parameters{"remote_commonname"} eq "")||
	($Current_Parameters{"remote_host"} eq "")||
	($Current_Parameters{"tcp_port"} eq "")||
	($Current_Parameters{"tcp_window_size"} eq "")){
	# not enough info
	return;
    }

    push @remote_commonname,$Current_Parameters{"remote_commonname"};
    push @remote_hostname,$Current_Parameters{"remote_host"};
    push @remote_datacommunicationport,$Current_Parameters{"tcp_port"};
    push @remote_tcpwindowsize,$Current_Parameters{"tcp_window_size"};
    if ($Current_Parameters{"evlbi_target"}){
	push @remote_evlbimode,$Current_Parameters{"evlbi_target"};
    } else {
	push @remote_evlbimode,0;
    }
    if ($Current_Parameters{"udp_datagram_size"}){
	push @remote_udpenabled,1;
    } else {
	push @remote_udpenabled,0;
    }
    push @remote_registered,0;

    &remotehost_display();

}

sub parameter_fileset {
    my $fill_window=$_[0];
    # set the contents of the selected window
    # using the contents of the cDisko config file
    for (my $i=0;$i<=$#settable_parameters;$i++){
	if (($settable_window[$i] eq $fill_window)||
	    ($settable_window[$i] eq "all")){
	    if ($settings->{$settable_parameters[$i]}){
		$Current_Parameters{$settable_parameters[$i]}=
		    $settings->{$settable_parameters[$i]};
	    }
	}
    }
}

sub advanced_window_ctl {
    $advanced->deiconify;
}

sub evlbi_window_ctl {
    $evlbi->deiconify;
    &parameter_fileset("evlbi");
}

sub recorder_window_ctl {
    $recorderwin->deiconify;
}

sub get_times {
    my $mjd = now2mjd();
    my $dayno;
    my ($day, $month, $year, $ut) = mjd2cal($mjd);
    ($dayno, $year, $ut) = mjd2dayno($mjd);
    my $str = turn2str($ut, 'H', 0);
    $ut_str = sprintf ("%d day %03d %s UT",$year,$dayno,$str);
    my $lst = mjd2lst($mjd, deg2turn($long_turns));
    $str = turn2str($lst, 'H', 0);
    $lst_str = sprintf ("%s LST",turn2str($lst, 'H', 0));
}

sub exit_program {
    # close_log
    close LOG;
    # unregister our listener
    &server_comms("cmnd","client-remove");
    # kill our listener child
    $SIG{CHLD} = 'IGNORE';
    kill ('INT', $cpid);
    waitpid($cpid,0);
    # kill our tail child
    kill ('INT', $tpid);
    waitpid($tpid,0);
    close($read_file);
    exit;
}

sub enter_comment {
    my $time=get_log_timestr();
    if (defined($comment)) {
	logit_blue("Sending message to server.\n");
	my $comm_result=&server_comms("mesg",$comment);
	if (&success($comm_result)){
	    logit_green("Message successfully sent.\n");
	} else {
	    logit_red("Unable to send message: $communication_error\n");
	}
	$comment = $time." ".$comment;
	$log_t->insert('end',"$comment\n");
	print LOG "$comment\n";
	$comment = "";
	$log_t->yview(moveto => 1);
	$log_t->update;
    }
}

sub get_log_timestr {
    my $mjd = now2mjd();
    my $dayno;
    my ($day, $month, $year, $ut) = mjd2cal($mjd);
    ($dayno, $year, $ut) = mjd2dayno($mjd);
    my $str = turn2str($ut, 'H', 0);
    while (length($str) < 8) {
	$str = "0".$str;
    }
    my $ut_str = sprintf ("%d.%03d.%s",$year,$dayno,$str);
    return ($ut_str);
}

sub get_logfile_timestr {
    my $mjd = now2mjd();
    my $dayno;
    my ($day, $month, $year, $ut) = mjd2cal($mjd);
    ($dayno, $year, $ut) = mjd2dayno($mjd);
    my $str = turn2str($ut, 'H', 0);
    while (length($str) < 8) {
	$str = "0".$str;
    }
    $str =~ s/\://g;
    $ut_str = sprintf ("%d_%03d_%s",$year,$dayno,$str);
    return ($ut_str);
}

sub set_mode_options {
    # this routine keeps the GUI consistent

    # check what options should be available for
    # channel selection, number of bits and
    # compression mode
    my $i;
    my $cfact;
    # how many active recorders?
    my $nactive_recs=0;
    for ($i=0;$i<=$#rec_servers;$i++){
	if ($recorder_active[$i]==1){
	    $nactive_recs++;
	}
    }
    # select the channel options based on current settings
    if ($Current_Parameters{"bandwidth"}<=16){
	if ($nactive_recs==1){ # one recorder
	    if ($huygens_cable==0){ # no Huygen's cable
		@rec_modes=@single_bw16_rec_modes;
		$chan_sel_entry->configure(-choices=>\@single_bw16_rec_modes,
					   -listheight=>$#single_bw16_rec_modes+1);
		@number_of_bits=@single_bw16_number_of_bits;
		$compress_entry->configure(-choices=>\@single_bw16_compress_modes,
					   -listheight=>$#single_bw16_compress_modes+1);
		@compress_modes=@single_bw16_compress_modes;
	    } else { # Huygen's cable in
		@rec_modes=@huygens_bw16_rec_modes;
		$chan_sel_entry->configure(-choices=>\@huygens_bw16_rec_modes,
					   -listheight=>$#huygens_bw16_rec_modes+1);
		@number_of_bits=@huygens_bw16_number_of_bits;
		$compress_entry->configure(-choices=>\@huygens_bw16_compress_modes,
					   -listheight=>$#huygens_bw16_compress_modes+1);
		@compress_modes=@huygens_bw16_compress_modes;
	    }
	} elsif ($nactive_recs==2){ # two recorders
	    @rec_modes=@double_bw16_rec_modes;
	    $chan_sel_entry->configure(-choices=>\@double_bw16_rec_modes,
				       -listheight=>$#double_bw16_rec_modes+1);
	    @number_of_bits=@double_bw16_number_of_bits;
	    $compress_entry->configure(-choices=>\@double_bw16_compress_modes,
				       -listheight=>$#double_bw16_compress_modes+1);
	    @compress_modes=@double_bw16_compress_modes;
	}
    } elsif ($Current_Parameters{"bandwidth"}==32){
	if ($nactive_recs==1){ # one recorder
	    if ($huygens_cable==0){ # no Huygen's cable
		@rec_modes=@single_bw32_rec_modes;
		$chan_sel_entry->configure(-choices=>\@single_bw32_rec_modes,
					   -listheight=>$#single_bw32_rec_modes+1);
		@number_of_bits=@single_bw32_number_of_bits;
		$compress_entry->configure(-choices=>\@single_bw32_compress_modes,
					   -listheight=>$#single_bw32_compress_modes+1);
		@compress_modes=@single_bw32_compress_modes;
	    } else { # Huygen's cable in
		@rec_modes=@huygens_bw32_rec_modes;
		$chan_sel_entry->configure(-choices=>\@huygens_bw32_rec_modes,
					   -listheight=>$#huygens_bw32_rec_modes+1);
		@number_of_bits=@huygens_bw32_number_of_bits;
		$compress_entry->configure(-choices=>\@huygens_bw32_compress_modes,
					   -listheight=>$#huygens_bw32_compress_modes+1);
		@compress_modes=@huygens_bw32_compress_modes;
	    }
	} elsif ($nactive_recs==2){ # two recorders
	    @rec_modes=@double_bw32_rec_modes;
	    $chan_sel_entry->configure(-choices=>\@double_bw32_rec_modes,
				       -listheight=>$#double_bw32_rec_modes+1);
	    @number_of_bits=@double_bw32_number_of_bits;
	    $compress_entry->configure(-choices=>\@double_bw32_compress_modes,
				       -listheight=>$#double_bw32_compress_modes+1);
	    @compress_modes=@double_bw32_compress_modes;
	}
    } elsif ($Current_Parameters{"bandwidth"}==64){
	if ($nactive_recs==1){ # one recorder
	    @rec_modes=@single_bw64_rec_modes;
	    $chan_sel_entry->configure(-choices=>\@single_bw64_rec_modes,
				       -listheight=>$#single_bw64_rec_modes+1);
	    @number_of_bits=@single_bw64_number_of_bits;
	    $compress_entry->configure(-choices=>\@single_bw64_compress_modes,
				       -listheight=>$#single_bw64_compress_modes+1);
	    @compress_modes=@single_bw64_compress_modes;
	} elsif ($nactive_recs==2){ # two recorders
	    @rec_modes=@double_bw64_rec_modes;
	    $chan_sel_entry->configure(-choices=>\@double_bw64_rec_modes,
				       -listheight=>$#double_bw64_rec_modes+1);
	    @number_of_bits=@double_bw64_number_of_bits;
	    $compress_entry->configure(-choices=>\@double_bw64_compress_modes,
				       -listheight=>$#double_bw64_compress_modes+1);
	    @compress_modes=@double_bw64_compress_modes;
	}
    }
    if ($nactive_recs==2){
	# disable selection of Huygen's cable
	$huygens_cable=0;
	$huygens_button->configure(-state => 'disabled');
    } else {
	# enable selection of Huygen's cable
	$huygens_button->configure(-state => 'normal');
    }

    # check if the scheduled start widgets should be
    # enabled/disabled
    if ($scheduled_start==1){
	# enable scheduled start widgets
	$y_e->configure(-state => 'normal');
	$d_e->configure(-state => 'normal');
	$h_e->configure(-state => 'normal');
	$m_e->configure(-state => 'normal');
	$s_e->configure(-state => 'normal');
    } elsif ($scheduled_start==0){
	# disabled widgets
	$y_e->configure(-state => 'disable');
	$d_e->configure(-state => 'disable');
	$h_e->configure(-state => 'disable');
	$m_e->configure(-state => 'disable');
	$s_e->configure(-state => 'disable');
    }

    # check which buttons should be enabled
    if ($server_manual_mode==1){
	# manual mode
	if ($recorder_status eq "Not recording"){
	    # not recording, enable start button, disable stop button
	    &enable_start("manual");
	} else {
	    # recording, enable stop button, disable start button
	    &enable_stop("manual");
	}
    } elsif ($server_manual_mode==0){
	# experiment mode
	if ($Current_Parameters{"auto_experiment"}==1){
	    # auto execution enabled, disable both start and stop buttons
	    &enable_start("experiment-auto");
	} elsif ($Current_Parameters{"auto_experiment"}==2){
	    # server has auto-stopped because of a problem
	    # enable start button
	    &enable_start("experiment-manual");
	} else {
	    # auto execution disabled
	    if ($recorder_status eq "Not recording"){
		# not recording, enable start button, disable stop button
		&enable_start("experiment-manual");
	    } else {
		# recording, enable stop button, disable start button
		&enable_stop("experiment-manual");
	    }
	}
    }

    # set defaults for health values if the recorder is
    # not running
    # default values for health values
    if ($tv_last_pps eq ""){
	$tv_last_pps="n/a";
    }
    if ($tv_stats eq ""){
	$tv_stats="- from last -";
    }
    if ($tv_last_bigbuf eq ""){
	$tv_last_bigbuf="n/a (n/a%)";
    }
    if ($tv_last_block eq ""){
	$tv_last_block="n/a";
    }

    # highlight the disk the data is being recorded to
    for (my $r=0;$r<=$#data_disks;$r++){
	my $backcolour=$value_bg;
	if (($r==$recording_to_disk)&&($recorder_status ne "Not recording")){
	    $backcolour='red';
	}
	$disks_buttons[$r]->configure(-background => $backcolour);
#	$disks_recorders[$r]->configure(-background => $backcolour);
	$disks_labels[$r]->configure(-background => $backcolour);
	$disks_sizes[$r]->configure(-background => $backcolour);
	$disks_remainings[$r]->configure(-background => $backcolour);
	$disks_lefts[$r]->configure(-background => $backcolour);
	$disks_times[$r]->configure(-background => $backcolour);
#	$disks_spaces[$r]->configure(-background => $backcolour);
    }

    # colour warnings
    if ($server_uptime eq "DOWN"){
	$uptime_label->configure(-foreground => 'red');
    } else {
	$uptime_label->configure(-foreground => 'black');
    }

}

sub set_record_mode {
    # determine the appropriate record mode based on the
    # fundamental settings VSIB mode and compression
    my $not_other=0;
    for (my $i=0;$i<$#rec_modes;$i++){
	if (($Current_Parameters{"vsib_bits"}==$number_of_bits[$i])&&
	    ($Current_Parameters{"compression"} eq $compress_modes[$i])){
	    $rec_mode=$rec_modes[$i];
	    $not_other=1; # a recognised setting
	    last;
	}
    }
    if ($not_other==0){
	# a custom setting, use the other mode
	$rec_mode=$rec_modes[$#rec_modes];
	&other_mode("enable");
    } else {
	&other_mode("disable");
    }
}

sub record_mode_set {
    # change the fundamental settings VSIB mode and compression
    # based on what the user has just chosen for the record
    # mode
    if ($rec_mode eq "Other"){
	&other_mode("enable");
    } else {
	&other_mode("disable");
	for (my $i=0;$i<=$#rec_modes;$i++) {
	    if ($rec_mode eq $rec_modes[$i]) {
		$Current_Parameters{"vsib_bits"} = $number_of_bits[$i];
		$Current_Parameters{"compression"} = $compress_modes[$i];
	    }
	}
    }
    &update_server; # enact the changes
}

sub other_mode {
    my $action=$_[0];

    if ($action eq "enable"){
#	$nbits_entry->configure(-state => 'normal', -disabledforeground => 'black');
#	$compress_entry->configure(-state => 'normal', -disabledforeground => 'black');	
	$nbits_entry->configure(-state => 'normal');

	$compress_entry->configure(-state => 'normal');
	$nbits_label->configure(-foreground => 'black');
	$compress_label->configure(-foreground => 'black');
    } elsif ($action eq "disable"){
	$nbits_entry->configure(-state => 'disabled');
	$compress_entry->configure(-state => 'disabled');
	$nbits_label->configure(-foreground => 'grey50');
	$compress_label->configure(-foreground => 'grey50');
    }
}

#sub start_cleaner{
#    logit_blue("Attempting to start new disk cleaner\n");
#    my $comm_result=&server_comms("cmnd","clean-start");
#    if (&success($comm_result)){
#	logit_green("Disk cleaner successfully started.\n");
#    } else {
#	logit_red("Unable to start disk cleaner: $communication_error\n");
#    }
#}

#sub stop_cleaner{
#    logit_blue("Attempting to stop most recently started disk cleaner\n");
#    my $comm_result=&server_comms("cmnd","clean-stop:1");
#    if (&success($comm_result)){
#	logit_green("Most recent disk cleaner successfully stopped.\n");
#    } else {
#	logit_red("Unable to stop disk cleaner: $communication_error\n");
#    }
#}

sub enable_start{
    my ($mode) = @_;
    if ($mode eq "manual"){
	$start_command="record-start";
	$start_button->configure(-state => 'normal');
    } elsif ($mode eq "experiment-manual"){
	$start_command="experiment-start";
	$start_button->configure(-state => 'normal');
    } elsif ($mode eq "experiment-auto"){
	$start_command="";
	$start_button->configure(-state => 'disable');
    }
    $stop_command="";
    $stop_button->configure(-state => 'disable');
}

sub enable_stop{
    my ($mode) = @_;
    if ($mode eq "manual"){
	$stop_command="record-stop";
	$stop_button->configure(-state => 'normal');
    } elsif ($mode eq "experiment-manual"){
	$stop_command="experiment-stop";
	$stop_button->configure(-state => 'normal');
    } elsif ($mode eq "experiment-auto"){
	$stop_command="";
	$stop_button->configure(-state => 'disable');
    }
    $start_command="";
    $start_button->configure(-state => 'disable');
}

sub load_experiment {
    my $exp_name=$ea_select;
    logit_blue("Attempting to load experiment $exp_name\n");
    my $comm_result=&server_comms("cmnd","experiment-load:$exp_name");
    if (&success($comm_result)){
	logit_green("Experiment loaded successfully.\n");
    } else {
	logit_red("Unable to load experiment: $communication_error\n");
    }
    return;
}

sub unload_experiment {
    my $exp_name=$el_select;
    logit_blue("Attempting to unload experiment $exp_name\n");
    my $comm_result=&server_comms("cmnd","experiment-unload:$exp_name");
    if (&success($comm_result)){
	logit_green("Experiment unloaded successfully.\n");
    } else {
	logit_red("Unable to unload experiment: $communication_error\n");
    }
    return;
}

sub logit {
    my ($text) = @_;
    $text = &get_log_timestr." ".$text;
    print LOG $text;
    logmsg($text);
    if ($debug) {print "$text";}
}

sub logit_red {
    my ($text) = @_;
    $text = &get_log_timestr." ".$text;
    print LOG $text;
    logmsg_red($text);
    if ($debug) {print "$text";}
}

sub logit_blue {
    my ($text) = @_;
    $text = &get_log_timestr." ".$text;
#    print LOG $text;
    # uncomment this next line if you want all messages concerning
    # what cDisko is trying to set
#    logmsg_blue($text);
    if ($debug) {print "$text";}
}

sub logit_green {
    my ($text) = @_;
    $text = &get_log_timestr." ".$text;
#    print LOG $text;
    # uncomment this next line if you want all messages concerning
    # successful operations with the server
#    logmsg_green($text);
    if ($debug) {print "$text";}
}

sub logmsg {
    $log_t->insert('end',@_);
    $log_t->yview(moveto => 1);
    $log_t->update;
}

sub logmsg_red {
#    print "BAD: @_\n";
    $log_t->insert('end',@_,'r');
    $log_t->yview(moveto => 1);
    $log_t->update;
}

sub logmsg_green {
    $log_t->insert('end',@_,'g');
    $log_t->yview(moveto => 1);
    $log_t->update;
}

sub logmsg_blue {
    $log_t->insert('end',@_,'b');
    $log_t->yview(moveto => 1);
    $log_t->update;
}

sub get_start_ydhms {
    my $mjd = now2mjd();
    $mjd+=10/86400; # add 10 seconds
    my $dayno;
    my ($day, $month, $year, $ut) = mjd2cal($mjd);
    ($dayno, $year, $ut) = mjd2dayno($mjd);
    my $str = turn2str($ut, 'H', 0);
    while (length($str) < 8) {
	$str = "0".$str;
    }
    $start_y = $year;
    $start_d = $dayno;
    ($start_h,$start_m,$start_s) = split ":", $str;
}

sub start_recording {
    # all the client needs to do to start recording is
    # tell the server to start recording!
    logit_blue("Starting recorder...\n");
    # first update the settings to the server
    &update_server();

    # set the start time if asked to do so
    if ($scheduled_start==0){
	# no scheduled start, reset the server's
	# scheduled start times
	logit_blue("Enabling immediate start.\n");
	my $comm_result=&server_comms("data","reset=record_start_date");
	if (!(&success($comm_result))){
	    logit_red("Unable to enable immediate start: $communication_error\n");
	    return;
	}
	$comm_result=&server_comms("data","reset=record_start_time");
	if (!(&success($comm_result))){
	    logit_red("Unable to enable immediate start: $communication_error\n");
	    return;
	}
	logit_green("Immediate start enabled.\n");
    } else {
	# scheduled start
	# for these settings, if they fail we aren't going to worry too much
	# (ie. don't stop recording). the most likely explanation is that the
	# start time is in the past, meaning the recording should start straight
	# away anyway - better to be recording now!
	logit_blue("Setting start date/time.\n");
	my $mjd = dayno2mjd($start_d,$start_y,0);
	my ($s_day,$s_month,$s_year,$s_ut)=mjd2cal($mjd);
	my $s_date;
	$s_date=sprintf("%4d%02d%02d",$s_year,$s_month,$s_day);
	my $comm_result=&server_comms("data","record_start_date=$s_date");
	if (!(&success($comm_result))){
	    logit_red("Unable to set start date: $communication_error\n");
	}
	my $s_time;
	$s_time=sprintf("%02d%02d%02d",$start_h,$start_m,$start_s);
	$comm_result=&server_comms("data","record_start_time=$s_time");
	if (!(&success($comm_result))){
	    logit_red("Unable to set start time: $communication_error\n");
	}
	logit_green("Start date/time successfully set.\n");
    }

    my $comm_result=&server_comms("cmnd",$start_command);
    if (!(&success($comm_result))){
	logit_red("Unable to start recorder: $communication_error\n");
    } else {
	logit_green("Recorder started.\n");
	my $rdisk=$Current_Parameters{"active_disk"};
	my $rlabel="";
	for (my $r=0;$r<=$#data_disks;$r++){
	    if ($rdisk eq $data_disks[$r]){
		$rlabel=$disk_label[$r];
	    }
	}
	&health_init("start");
	# and disable scheduled start now so that when the recorder stops (which
	# will most likely be after the scheduled start time), another recorder
	# start command will work as expected
	$scheduled_start=0;
    }

    # show the recording settings window
    &recorder_window_ctl();

    $get_recorder_command=1;
    &server_update();
}

sub health_init{
    my $action = $_[0];
    if ($action eq "start"){
	$stats_repeat=$stats_frame->repeat(1000,\&check_health);
    } elsif ($action eq "stop"){
	$stats_frame->afterCancel($stats_repeat);
    }
}

sub check_health {

    my @pels=split(/\s+/,$tv_stats);
    if ($pels[0] ne "-"){
	# haven't got info yet
	if ($pels[0]>=$n_pps_warn){
	    $too_many_missed_pps=1;
	} else {
	    $too_many_missed_pps=0;
	}
	if ($too_many_missed_pps && !$too_many_missed_pps_msg_started) {
	    # bring up a dialog and beep
	    print "\n\n\nstart pps dialog\n\n\n";
	    if (!$start_pps_dialog) {$start_pps_dialog = 1;}
	}
    }

    my @bels=split(/\s+/,$tv_last_bigbuf);
    my $last_bigbuf_free_percent=$bels[$#bels];
    if ($last_bigbuf_free_percent ne "(n/a%)"){
	$last_bigbuf_free_percent=~s/\((\d*)\%\)/$1/;
	# check BIGBUF size
	if ($last_bigbuf_free_percent >= $settings->{'bigbuf_warn_limit'}) {
	    # bigbuf OK. Set default parameters
	    if ($bigbuf_panic_msg_started) {
		logit "Bigbuf levels OK: $last_bigbuf_free_percent%\n";
	    }
	    $warned_bigbuf_free_percent=0;
	    $bigbuf_panic_msg_started = 0;
	    $start_bigbuf_dialog = 0;
	} elsif ($last_bigbuf_free_percent < $settings->{'bigbuf_panic_limit'}) {
	    # bring up a dialog and beep
	    logit_red "Bigbuf level is very low: $last_bigbuf_free_percent%\n";
	    if (!$bigbuf_panic_msg_started) {
		$bigbuf_panic_msg_started = 1;
		$start_bigbuf_dialog = 1;
	    }
	} else {
	    # bigbuf is between bigbuf_warn_limit and bigbuf_panic_limit
	    if ($last_bigbuf_free_percent != $warned_bigbuf_free_percent){
		logit_red "Bigbuf level is low: $last_bigbuf_free_percent%\n";
		$warned_bigbuf_free_percent=$last_bigbuf_free_percent;
		$main->bell();
	    }
	    $bigbuf_panic_msg_started = 0;
	}
    }
    
    # what's the capacity of the active disk?
#    my $perc_full;
#    for (my $r=0;$r<=$#data_disks;$r++){
#	if (($Current_Parameters{"active_disk"} eq $data_disks[$r])||
#	    ($Current_Parameters{"active_disk"} eq $data_recorders[$r].":".$data_disks[$r])){
#	    my $free_perc=$disk_perc_free[$r];
#	    $free_perc=~s/\%//;
#	    $perc_full=100.0-$free_perc;
#	    last;
#	}
#    }
    if (($recorder_status ne "Not recording")&&
	($rec_perc_free ne "")){
	# only warn about full disks when recording to them
	my $perc_full=100.0-$rec_perc_free;
	if ($perc_full > 95) {
	    # volume of active disk is greater than the limit
	    # bring up a dialog and beep
	    if (!$disk_full_msg_started) {
		$start_fulldisk_dialog = 1;
		$disk_full_msg_started = 1;
	    }
	    if (time>$disks_warning_time+60){
		my $d = sprintf "Disk space getting low: %5.1f percent.\n",$perc_full;
		logit_red $d;
		$disks_warning_time=time;
	    }
	} else {
	    if ($disk_full_msg_started) {
		my $d = sprintf "Disk space now OK: %5.1f percent.\n",$perc_full;
		logit_red $d;
	    }
	    $disk_full_msg_started = 0;
	}
    }
#    }
}

sub stop_recording {
    # the stop routine just needs to tell the server
    # to stop the recorder
    logit_blue("Stopping recorder...\n");
    my $comm_result=&server_comms("cmnd",$stop_command);
    if (!(&success($comm_result))){
	logit_red("Unable to stop recorder: $communication_error\n");
    } else {
	logit_green("Recorder stopped.\n");
	&health_init("stop");
    }

    &server_update();
}

sub start_dialogs {
    # depending on signals, will start appropriate dialogs
    if ($errorwin_free) {
	if ($start_pps_dialog) {
	    $too_many_missed_pps_msg_started = 1;
	    $start_pps_dialog = 0;
	    tk_error("More than $n_pps_warn of the last $n_pps_remember 1PPS checks have been missed.\nPlease investigate the problem\n");
	    $errorwin_free = 0;
	} elsif ($start_bigbuf_dialog) {
	    $bigbuf_panic_msg_started = 1;
	    $start_bigbuf_dialog = 0;
	    tk_error("The capacity of BIGBUF is now $last_bigbuf_free_percent% which is very low.\n Vsib_record may die soon and requre restarting.\n Consider stopping recording and investigate the problem\n");
	    $errorwin_free = 0;
	} elsif ($start_fulldisk_dialog) {
	    $disk_full_msg_started = 1;
	    $start_fulldisk_dialog = 0;
	    my $d = sprintf "Disk capacity has exceeded %d percent.\nConsider deleting old files or stopping recording and changing disks.\n",95;
	    tk_error($d);
	    $errorwin_free = 0;
	} elsif ($start_missing_file_dialog) {
	    $missed_file_msg_started = 1;
	    $start_missing_file_dialog = 0;
	    tk_error("Vsib_record has missed opening a data file.\nThis is probably a serious problem, please investigate.\n");
	    $errorwin_free = 0;
	}
    }
}

sub tk_error {
    $err_msg->configure(-text => @_);
    $errorwin->deiconify;
    $err_msg->bell;
    $err_msg->bell;
    $err_msg->bell;
    $err_msg->bell;
    $err_msg->bell;
}

sub strip_fail {
    my ($mesg) = @_;
    $mesg=~s/\<fail\>//;
    $mesg=~s/\<\/fail\>(.*)//;
    return ($mesg);
}

sub change_disks {
    my $change_to_disks=$_[0];
    for (my $r=0;$r<=$#data_disks;$r++){
	$disks_buttons[$r]->gridForget($disks_labels[$r],$disks_recorders[$r],$disks_sizes[$r],
				       $disks_remainings[$r],$disks_lefts[$r],
				       $disks_times[$r],$disks_spaces[$r]);
    }

    &contact_server();
    &get_available_disks($server_response);
    &disks_display();
    for (my $i=0;$i<=$#settable_parameters;$i++){
	$Current_Parameters{$settable_parameters[$i]}=&get_param($settable_parameters[$i]);
    }
    if ($recorder_status ne "Not recording"){
	for (my $i=0;$i<=$#settable_parameters;$i++){
	    $Current_Parameters{"rs_$settable_parameters[$i]"}=&get_param("rs_$settable_parameters[$i]");
	}
    }

    # make sure the GUI is consistent with itself
    &set_mode_options();
    &set_record_mode();
}

sub disks_display {
    if ($in_startup==1){
	$disks_frame->Label(-relief => 'flat',
			    -font => $boldfont,
			    -text => "Recorder",
			    -background => $value_bg)
	    ->grid(-column => 0, -row => 0, -sticky => 'ew');
	$disks_frame->Label(-relief => 'flat', 
			    -font => $boldfont, 
			    -text => "Disk Name", 
			    -background => $value_bg)
	    ->grid(-column => 1, -row => 0, -sticky => 'ew');
	$disks_frame->Label(-relief => 'flat',
			    -font => $boldfont,
			    -text => "Disk Label",
			    -background => $value_bg)
	    ->grid(-column => 2, -row => 0, -sticky => 'ew');
	$disks_frame->Label(-relief => 'flat', 
			    -font => $boldfont, 
			    -text => "Size", 
			    -background => $value_bg)
	    ->grid(-column => 3, -row => 0, -sticky => 'ew');
	$disks_frame->Label(-relief => 'flat', 
			    -font => $boldfont, 
			    -text => "Remaining", 
			    -background => $value_bg)
	    ->grid(-column => 4, -row => 0, -sticky => 'ew');
	$disks_frame->Label(-relief => 'flat', 
			    -font => $boldfont, 
			    -text => " % left ", 
			    -background => $value_bg)
	    ->grid(-column => 5, -row => 0, -sticky => 'ew');
	$disks_frame->Label(-relief => 'flat', 
			    -font => $boldfont, 
			    -text => " Time left (h:m:s) ", 
			    -background => $value_bg)
	    ->grid(-column => 6, -row => 0, -sticky => 'ew');
	# and in the recorder status window
	$recdisk_frame->Label(-relief => 'flat',
			    -font => $boldfont,
			    -text => "Recorder",
			    -background => $value_bg)
	    ->grid(-column => 0, -row => 0, -sticky => 'ew');
	$recdisk_frame->Label(-relief => 'flat', 
			    -font => $boldfont, 
			    -text => "Disk Name", 
			    -background => $value_bg)
	    ->grid(-column => 1, -row => 0, -sticky => 'ew');
	$recdisk_frame->Label(-relief => 'flat',
			    -font => $boldfont,
			    -text => "Disk Label",
			    -background => $value_bg)
	    ->grid(-column => 2, -row => 0, -sticky => 'ew');
	$recdisk_frame->Label(-relief => 'flat', 
			    -font => $boldfont, 
			    -text => "Size", 
			    -background => $value_bg)
	    ->grid(-column => 3, -row => 0, -sticky => 'ew');
	$recdisk_frame->Label(-relief => 'flat', 
			    -font => $boldfont, 
			    -text => "Remaining", 
			    -background => $value_bg)
	    ->grid(-column => 4, -row => 0, -sticky => 'ew');
	$recdisk_frame->Label(-relief => 'flat', 
			    -font => $boldfont, 
			    -text => " % left ", 
			    -background => $value_bg)
	    ->grid(-column => 5, -row => 0, -sticky => 'ew');
	$recdisk_frame->Label(-relief => 'flat', 
			    -font => $boldfont, 
			    -text => " Time left (h:m:s) ", 
			    -background => $value_bg)
	    ->grid(-column => 6, -row => 0, -sticky => 'ew');
	$recdisk_frame->Label(-relief => 'flat',
			      -font => $font,
			      -textvariable => \$rec_recorder,
			      -background => $value_bg)
	    ->grid(-column => 0, -row => 1, -sticky => 'w');
	$recdisk_frame->Label(-relief => 'flat',
			      -font => $font,
			      -textvariable => \$rec_disk,
			      -background => $value_bg)
	    ->grid(-column => 1, -row => 1, -sticky => 'w');
	$recdisk_frame->Label(-relief => 'flat',
			      -font => $font,
			      -textvariable => \$rec_label,
			      -background => $value_bg)
	    ->grid(-column => 2, -row => 1, -sticky => 'ew');
	$recdisk_frame->Label(-relief => 'flat',
			      -font => $font,
			      -textvariable => \$rec_total,
			      -background => $value_bg)
	    ->grid(-column => 3, -row => 1, -sticky => 'ew');
	$recdisk_frame->Label(-relief => 'flat',
			      -font => $font,
			      -textvariable => \$rec_avail,
			      -background => $value_bg)
	    ->grid(-column => 4, -row => 1, -sticky => 'ew');
	$recdisk_frame->Label(-relief => 'flat',
			      -font => $font,
			      -textvariable => \$rec_perc_free,
			      -background => $value_bg)
	    ->grid(-column => 5, -row => 1, -sticky => 'ew');
	$recdisk_frame->Label(-relief => 'flat',
			      -font => $font,
			      -textvariable => \$rec_timeleft,
			      -background => $value_bg)
	    ->grid(-column => 6, -row => 1, -sticky => 'ew');

    }
    for (my $r = 1; $r <= $#data_disks+1; $r++) {
	$disks_recorders[$r-1]=$disks_frame->Label(-relief => 'flat',
						   -font => $font,
						   -textvariable => \$data_recorders[$r-1],
						   -background => $value_bg)
	    ->grid(-column => 0, -row => $r, -sticky => 'w');
	$disks_buttons[$r-1]=$disks_frame->Radiobutton(-text => "$data_disks[$r-1]", 
						       -font => $font, 
						       -variable => \$Current_Parameters{"active_disk"},
						       -value => "$data_recorders[$r-1]:$data_disks[$r-1]",
						       -command => \&update_server,
						       -background => $value_bg)
	    ->grid(-column => 1, -row => $r, -sticky => 'w');
	$disks_labels[$r-1]=$disks_frame->Label(-relief => 'flat',
						-font => $font,
						-textvariable => \$disk_label[$r-1],
						-background => $value_bg)
	    ->grid(-column => 2, -row => $r, -sticky => 'ew');
	$disks_sizes[$r-1]=$disks_frame->Label(-relief => 'flat', 
					       -font => $font, 
					       -textvariable => \$disk_total[$r-1],
					       -background => $value_bg)
	    ->grid(-column => 3, -row => $r, -sticky => 'ew');
	$disks_remainings[$r-1]=$disks_frame->Label(-relief => 'flat', 
						    -font => $font, 
						    -textvariable => \$disk_avail[$r-1],
						    -background => $value_bg)
	    ->grid(-column => 4, -row => $r, -sticky => 'ew');
	$disks_lefts[$r-1]=$disks_frame->Label(-relief => 'flat', 
					       -font => $font, 
					       -textvariable => \$disk_perc_free[$r-1],
					       -background => $value_bg)
	    ->grid(-column => 5, -row => $r, -sticky => 'ew');
	$disks_times[$r-1]=$disks_frame->Label(-relief => 'flat',
					       -font => $font, 
					       -textvariable => \$disk_time_left[$r-1],
					       -background => $value_bg)
	    ->grid(-column => 6, -row => $r, -sticky => 'ew');
	$disks_spaces[$r-1]=$diskspace_warning[$r-1]=$disks_frame->Label(-relief => 'flat',
									 -font => $boldfont,
									 -text => "LOW SPACE!",
									 -background => $value_bg,
									 -foreground => $value_bg)
	    ->grid(-column => 7, -row => $r, -sticky => 'ew');
    }

}

sub remotehost_display {
    if ($in_startup==1){
	$remote_frame->Label(-relief => 'flat',
			     -font => $boldfont,
			     -text => "Recorder",
			     -background => $value_bg)
	    ->grid(-column => 0, -row => 0, -sticky => 'ew');
	$remote_frame->Label(-relief => 'flat',
			     -font => $boldfont,
			     -text => "Hostname",
			     -background => $value_bg)
	    ->grid(-column => 1, -row => 0, -sticky => 'ew');
	$remote_frame->Label(-relief => 'flat',
			     -font => $boldfont,
			     -text => "Port",
			     -background => $value_bg)
	    ->grid(-column => 2, -row => 0, -sticky => 'ew');
	$remote_frame->Label(-relief => 'flat',
			     -font => $boldfont,
			     -text => "TCP Window Size",
			     -background => $value_bg)
	    ->grid(-column => 3, -row => 0, -sticky => 'ew');
	$remote_frame->Label(-relief => 'flat',
			     -font => $boldfont,
			     -text => "eVLBI",
			     -background => $value_bg)
	    ->grid(-column => 4, -row => 0, -sticky => 'ew');
	$remote_frame->Label(-relief => 'flat',
			     -font => $boldfont,
			     -text => "UDP",
			     -background => $value_bg)
	    ->grid(-column => 5, -row => 0, -sticky => 'ew');
	$remote_frame->Label(-relief => 'flat',
			     -font => $boldfont,
			     -text => "Status",
			     -background => $value_bg)
	    ->grid(-column => 6, -row => 0, -sticky => 'ew');
    }
    for (my $r=1;$r<=$#remote_commonname;$r++){
	if ($remote_commonname[$r] ne ""){
	    $remote_frame->Label(-text => $remote_commonname[$r],
				 -font => $font,
				 -background => $value_bg)
		->grid(-column => 0, -row => $r, -sticky => 'w');
	    $remote_frame->Label(-text => $remote_hostname[$r],
				 -font => $font,
				 -background => $value_bg)
		->grid(-column => 1, -row => $r, -sticky => 'w');
	    $remote_frame->Label(-text => $remote_datacommunicationport[$r],
				 -font => $font,
				 -background => $value_bg)
		->grid(-column => 2, -row => $r, -sticky => 'ew');
	    $remote_frame->Label(-text => $remote_tcpwindowsize[$r],
				 -font => $font,
				 -background => $value_bg)
		->grid(-column => 3, -row => $r, -sticky => 'ew');
	    my $tmp_string;
	    if ($remote_evlbimode[$r]==1){
		$tmp_string="Yes";
	    } else {
		$tmp_string="No";
	    }
	    $remote_frame->Label(-text => $tmp_string,
				 -font => $font,
				 -background => $value_bg)
		->grid(-column => 4, -row => $r, -sticky => 'ew');
	    if ($remote_udpenabled[$r]==1){
		$tmp_string="Yes";
	    } else {
		$tmp_string="No";
	    }
	    $remote_frame->Label(-text => $tmp_string,
				 -font => $font,
				 -background => $value_bg)
		->grid(-column => 5, -row => $r, -sticky => 'ew');
	    if ($remote_registered[$r]==1){
		$remote_frame->Label(-text => "Enabled",
				     -font => $font,
				     -background => $value_bg)
		    ->grid(-column => 6, -row => $r, -sticky => 'ew');
		$remote_frame->Button(-text => "Disable",
				      -font => $boldfont,
				      -command => [\&remotehost_actions,"disable,$r"],
				      -background => 'red')
		    ->grid(-column => 7, -row => $r, -sticky => 'ew');
	    } else {
		$remote_frame->Label(-text => "Disabled",
				     -font => $font,
				     -background => $value_bg)
		    ->grid(-column => 6, -row => $r, -sticky => 'ew');
		$remote_frame->Button(-text => "Enable",
				      -font => $boldfont,
				      -command => [\&remotehost_actions,"enable,$r"],
				      -background => 'green')
		    ->grid(-column => 7, -row => $r, -sticky => 'ew');
	    }
	}
    }
}

sub remotehost_actions {
    my ($string)=@_;
    # go through the remote hosts we know about
    $string=~/(.*),(\d+)/;
    my $action=$1;
    my $number=$2;
    if ($action eq "enable"){
	# add a host
	my $comm_result=
	    &server_comms("data","add_host=$remote_commonname[$number],".
			  "$remote_hostname[$number],$remote_datacommunicationport[$number],".
			  "$remote_tcpwindowsize[$number],$remote_evlbimode[$number],".
			  "$remote_recorderserverport[$number]");
	if (&success($comm_result)){
	    if ($remote_udpenabled[$number]!=0){
		$comm_result=
		    &server_comms("data","modify_host=$remote_commonname[$number],".
				  "$remote_udpenabled[$number],$remote_ipd[$number]");
		if (&success($comm_result)){
		    logit_green("Remote host $remote_commonname[$number] enabled.\n");
		    $remote_registered[$number]=1;
		} else {
		    logit_red("Unable to enable $remote_commonname[$number]: $communication_error\n");
		    $comm_result=&server_comms("data","rem_host=$remote_commonname[$number]");
		    $remote_registered[$number]=0;
		}
	    } else {
		logit_green("Remote host $remote_commonname[$number] enabled.\n");
		$remote_registered[$number]=1;
	    }
	} else {
	    logit_red("Unable to enable $remote_commonname[$number]: $communication_error\n");
	    $remote_registered[$number]=0;
	}
    } elsif ($action eq "disable"){
	# remove this host
	if ($remote_registered[$number]!=0){
	    my $comm_result=
		&server_comms("data","rem_host=$remote_commonname[$number]");
	    if (&success($comm_result)){
		logit_green("Remote host $remote_commonname[$number] disabled.\n");
		$remote_registered[$number]=0;
	    } else {
		logit_red("Unable to disable $remote_commonname[$number]: $communication_error\n");
		$remote_registered[$number]=1;
	    }
	}
    }
}
